java内存回收问题 OutOfMemoryError: Java heap space

warcao 2012-04-19 08:19:25
现在有代码
String str = new String("abc");
String str1 = str;

那我如果str1 = null;那么str的内存是不是不会得到回收?
怎么回收str的空间呢?
我有一个好几千万的循环,所以需要及时的回收内存。
实际问题就是读文件,文件几千万行,堆现在是256m,不希望继续扩了。
while ((oneLine = reader.readLine()) != null)
这一行会报内存不足 java.lang.OutOfMemoryError: Java heap space
查看了readLine的源代码,里面会new一个string,类似上述的问题,所以发这个帖子求助大家。

...全文
380 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
VanBaston 2012-04-20
  • 打赏
  • 举报
回复
数据量大的话建议是读取一部分处理一部分,而不要一次读取完成了才去处理。
MiceRice 2012-04-20
  • 打赏
  • 举报
回复
楼主,把这个数据直接存入数据库吧,看你用HashMap肯定是想做快速查找;

但这个量太大,建议存入轻量级数据库(你这种KV型的,甚至可以用NoSQL),后续借助数据库来快速查找,效率也很高的。

另一种方案是用MemCache/EHCache这种开源缓存组件,然后开启本地磁盘缓存能力,就可以超越内存容量限制。
安特矮油 2012-04-20
  • 打赏
  • 举报
回复
数据量太大,想完全放倒内存当中是个问题,建议考虑用别的方法。要么就优化部分算法以及继续扩大JVM的堆内存。
MiceRice 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]
740m
[/Quote]

这个规模。。。我想很难完整装载进JVM了,尤其是你还想节省内存的话。

List和Map自己的内存结构都是不小的开销,尤其Map有大量指针存储开销。

你可以测试看看,把List和Map都去掉,哪怕把内存降低为128MB,也能正常跑完的。

ArrayList value = map.get(FollowerId);
/*if(value == null) {
ArrayList arrayList = new ArrayList();
arrayList.add(FolloweeId);
map.put(FollowerId, arrayList);
}*/

要么就要用64位JVM,继续放大内存;要么就得换种算法了。
sjlzcj 2012-04-19
  • 打赏
  • 举报
回复
把具体需求描述一下吧

如果你的文件 很大 比如 10G 的文件 那么你如何修改 JVM内存都白费了

考虑下 散列文件
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]

哦,说浪费速度和对像数量是一回事,不过你考虑了对象自身大小,确实Integer比String小,不过不止16b,应该是32b,另外还需要包括对象自身容量;毕竟它不是int这种基础类型。

你的文件大小是多少?
[/Quote]
740m
MiceRice 2012-04-19
  • 打赏
  • 举报
回复
哦,说浪费速度和对像数量是一回事,不过你考虑了对象自身大小,确实Integer比String小,不过不止16b,应该是32b,另外还需要包括对象自身容量;毕竟它不是int这种基础类型。

你的文件大小是多少?
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]

这种局部资源释放都不会是问题,不过既然你是存入Map和List,其实可以不需要parseInt(),浪费速度和对象数量。

逻辑错误是指如果value不是null,你就完全抛弃这个节点了。
ArrayList value = map.get(FollowerId);
if(value == null) {
ArrayList arrayList = new Ar……
[/Quote]
我put map.put(FollowerId 这里是安装integer大小算的吗 就是16b?
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]

这种局部资源释放都不会是问题,不过既然你是存入Map和List,其实可以不需要parseInt(),浪费速度和对象数量。

逻辑错误是指如果value不是null,你就完全抛弃这个节点了。
ArrayList value = map.get(FollowerId);
if(value == null) {
ArrayList arrayList = new Ar……
[/Quote]

哦不好意思忘了一个else
else
{
value.add(FolloweeId);
}

另外 其实可以不需要parseInt(),浪费速度和对象数量
这句不理解?
MiceRice 2012-04-19
  • 打赏
  • 举报
回复
这种局部资源释放都不会是问题,不过既然你是存入Map和List,其实可以不需要parseInt(),浪费速度和对象数量。

逻辑错误是指如果value不是null,你就完全抛弃这个节点了。
ArrayList value = map.get(FollowerId);
if(value == null) {
ArrayList arrayList = new ArrayList();
arrayList.add(FolloweeId);
map.put(FollowerId, arrayList);
}
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]

引用 11 楼 的回复:

基本没招。。。你这个是硬性内存要求。你文件总规模多大?

另外你这么用StringBuffer意义不大,反而损耗性能,直接:
String cuts[] = oneLine.split("\t");
就得到两个字符串,然后:
FollowerId = Integer.valueOf(cuts[0]);
FolloweeId = Integer.val……
[/Quote]

现在1g的堆内存 运行到260w行就告溢出 不应该呀
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

基本没招。。。你这个是硬性内存要求。你文件总规模多大?

另外你这么用StringBuffer意义不大,反而损耗性能,直接:
String cuts[] = oneLine.split("\t");
就得到两个字符串,然后:
FollowerId = Integer.valueOf(cuts[0]);
FolloweeId = Integer.valueOf(cuts[1]);

……
[/Quote]
我内存跳到1g了 还是不行 因为有后序处理 所以这一步不能使用太多的内存
文件总规模: 5000w个 int \t int
String cuts[] = oneLine.split("\t"); 使用这个也会内存溢出,因为split底层使用的substring会引用分割前大的string的char数组,导致空间不足
逻辑错误是指使用arraylist吗
主要是要处理一对多的
MiceRice 2012-04-19
  • 打赏
  • 举报
回复
基本没招。。。你这个是硬性内存要求。你文件总规模多大?

另外你这么用StringBuffer意义不大,反而损耗性能,直接:
String cuts[] = oneLine.split("\t");
就得到两个字符串,然后:
FollowerId = Integer.valueOf(cuts[0]);
FolloweeId = Integer.valueOf(cuts[1]);


然后还突然发现你最后那个构建哈希表应该有逻辑错误。
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

从你的程序来看,应该是map内存溢出了,文件几千万行,你转成String对象后,全部要存入map的List中,意味着整个文件实际上全部存入JVM内存了。

不信的话,把这三句话注释掉,肯定不溢出了:
ArrayList arrayList = new ArrayList();
arrayList.add(FolloweeId);
map.put(FollowerId, arrayLis……
[/Quote]
但是任务要求必须要建立hash表呀
有什么办法吗
MiceRice 2012-04-19
  • 打赏
  • 举报
回复
从你的程序来看,应该是map内存溢出了,文件几千万行,你转成String对象后,全部要存入map的List中,意味着整个文件实际上全部存入JVM内存了。

不信的话,把这三句话注释掉,肯定不溢出了:
ArrayList arrayList = new ArrayList();
arrayList.add(FolloweeId);
map.put(FollowerId, arrayList);
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

引用 5 楼 的回复:

应该不是这里的问题,请把你完整程序贴出来。

帮我看看哪里内存使用出了问题
Java code

while ((oneLine = reader.readLine()) != null)
{

int idx = oneLine.indexOf('\t');
……
[/Quote]

补充下 文件格式是 两个int
11111111 3456
我是要分隔 然后把int放入hash表
warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

应该不是这里的问题,请把你完整程序贴出来。
[/Quote]
帮我看看哪里内存使用出了问题

while ((oneLine = reader.readLine()) != null)
{

int idx = oneLine.indexOf('\t');
for(int i = 0; i < idx; i++)
{
strBuffer1.append(oneLine.charAt(i));
}
for(int i = idx + 1,len = oneLine.length(); i < len; i++)
{
strBuffer2.append(oneLine.charAt(i));
}

FollowerId = Integer.valueOf(strBuffer1.toString()).intValue();
FolloweeId = Integer.valueOf(strBuffer2.toString()).intValue();
strBuffer1.delete(0, strBuffer1.length());
strBuffer2.delete(0, strBuffer2.length());
oneLine = null;
//构建哈希表
ArrayList value = map.get(FollowerId);
if(value == null)
{
ArrayList arrayList = new ArrayList();
arrayList.add(FolloweeId);
map.put(FollowerId, arrayList);
}
}

warcao 2012-04-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

oneLine=null,只是oneLine不引用其他对象,但只要该对象还被其他变量引用着,就不会被回收。
如果文件不大的话,可能程序其他地方也占用了大量内存,这里只是加剧了内存占用,是导火索
[/Quote]

reader.readLine()确实是导火线 文件很大 5000w条 但是每条记录就是两个int
MiceRice 2012-04-19
  • 打赏
  • 举报
回复
应该不是这里的问题,请把你完整程序贴出来。
cseu 2012-04-19
  • 打赏
  • 举报
回复
oneLine=null,只是oneLine不引用其他对象,但只要该对象还被其他变量引用着,就不会被回收。
如果文件不大的话,可能程序其他地方也占用了大量内存,这里只是加剧了内存占用,是导火索
加载更多回复(3)

62,612

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧