大家来帮我看看这个 java 内存问题吧,我快崩溃了。

2014-08-31 21:53:55 +08:00
 buptlee
程序的开始是读入一个文件里的数据,数据的格式是:
每一行为三个字段,例如:
2,3,0
并且1-50行的第一个数字相同,51-100行的第一个数字相同,以此类推。
一共是1.2亿行。我把它读到一个字典里面。我用的数据结构是:HashMap<Integer,LinkedList<Node>>
键是每一行的第一个数字,值是一个LinkedList,Node有两个字段:
Node{
int ID;
int distance;
}
分别是每一行的第二个数字和第三个数字。也就是说每一行会产生一个node。
然后每50行放入一个LinkedList,再put进hashmap里面。我估算了一下,需要的内存是:
0.12G*(4+4+4)=1.44G
4是int类型占的字节数。加上node封装,linkedlist的使用可能会需要一些额外的内存,我给java虚拟机分配了6G的内存上线。
程序运行的时候,发现开始读入的速度还是很快的,内存涨的很快,但cpu一直维持在较低水平,大概40-50%,但是当读入到2300万行的时候就卡主了,多次运行到这时都停住了,任务管理器显示java程序只占用了2.3G的内存,但很快cpu使用率达到了100%。
我想问下大家,这是什么原因呢,是因为我使用了Node封装和LinkedList导致需要更多的内存吗。需要多多少呢。而且为什么我为这个java程序分配了6g的内存,就算是内存不足,也不应该卡在2.3G这个地方啊。难道是我分配内存的方法不对?大家都是怎么给某个java程序单独分配内存的?
拜谢各位啊。
6248 次点击
所在节点    Java
21 条回复
plucury
2014-08-31 22:22:32 +08:00
怀疑是内存问题可以用jmap打印内存占用情况。但是既然cpu占用100%的话,可以考虑用jstack打印线程运行命令来看看,如果看起来没问题考虑启动时打印GC日志,看看是否有频繁的full gc
cloud107202
2014-08-31 22:39:56 +08:00
内存问题不是很了解,说点我想到的
1. 插入过程有没有并发调用HashMap.get(),这个可能会发生死锁http://coolshell.cn/articles/9606.html
2. 如果可能的话,考虑下redis这类内存数据库
undeflife
2014-08-31 23:15:17 +08:00
如果是内存问题的话 应该会报OOM 或OOM:PermGen space的

查查文件在2300万行左右是否有什么问题导致你在读取文件的时候卡住
读取文件的代码会不会有什么bug引起问题
怀疑LinkedList 的话完全可以把LinkedList换成Node[50]
ahcat
2014-08-31 23:25:15 +08:00
换一个64位的jvm?
buptlee
2014-08-31 23:36:54 +08:00
@ahcat 就是64bit啊。嘿嘿。
lehui99
2014-09-01 00:10:58 +08:00
HashMap的内部实现是数组+链表,在key的数量扩大时有可能导致数组和所有链表的内存重新分配,并将其中所有的引用重新赋值到新的数组中并重新生成所有的链表,十分耗时。可以看一下HashMap的具体实现的详细分析: http://blog.csdn.net/blog/vking_wang/14166593 ,中的最后一段:rehash过程。
解决方法是在HashMap初始化时指定initCap,如: new HashMap(130000000/50) 。
akfish
2014-09-01 06:09:39 +08:00
数据固定么?需要改动么?改了需要写回文件么?
既然数据格式已知,完全没必要用HashMap和LinkedList,直接分配一个巨大的Array,减少overhead。对应key的index很容易计算,或者用一个HashMap<Integer, Integer>来记录每个key的第一个index。
另外就是一次完成分配可以提高分配到连续内存的概率,减少碎片的产生。
nybux
2014-09-01 08:43:50 +08:00
HashMap在构造的时候加个参数
new HashMap<>(2400001);
buptlee
2014-09-01 09:20:19 +08:00
@lehui99 好的,试试看。谢谢兄弟。
stevenyou
2014-09-01 09:27:39 +08:00
楼主对内存的估算不太正确, 没有算进去java object , 和HashMap 的overhead.
一个空object 会用16 bytes, Node 里有两个int, 也就是一个Node 会在Heap里用掉32 bytes
一个空LinkedList里应该有4个private fields 会占用 (4+2) * 8 = 48 bytes
一个LinkedList用的memroy 是 48 + 24* size_of_list , 你的size 是50 , 也就是 1248 bytes

HashMap 的内存占用是 32 * SIZE + 4 * CAPACITY bytes , 你的size 是 120,000,000 / 50 . default load factor 是0.75, capacity 就是 (120,000,000 / 50) / 0.75.

估算一下, 一共会用7个多G 的内存。

另外hashmap rehash 是很快的,这个数据量不是很大, cpu没有吃满应该是别的原因,比如disk io, 看一下你top 里的 wa 是多少。

楼主也可以把代码贴出来给大家看看,分析一下。
buptlee
2014-09-01 09:31:35 +08:00
@cloud107202 没有并发问题,有没有redis的入门资料呢,贴个链接啥的,不太懂这个,嘿嘿。
stevenyou
2014-09-01 09:32:21 +08:00
cpu使用率后来达到了100% 应该是在rehash
buptlee
2014-09-01 09:38:19 +08:00
@stevenyou 贴出来啦,您给看看。嘿嘿。
stevenyou
2014-09-01 09:52:25 +08:00
@buptlee 应该没什么问题, 像 @lehui99 说的在HashMap初始化时指定initCap 应该可以解决这个问题。
建议是,如果你对内存使用在意的话,可以使用别的一些数据类型(Gnu Trove 里的TIntObjectHashMap, TIntArrayList etc. )在几乎不损失性能的同时把总内存降低到2G ~ 3G
stevenyou
2014-09-01 09:53:13 +08:00
buptlee
2014-09-01 10:06:02 +08:00
@stevenyou 我试了在声明hashmap时初始化个数的方法:
HashMap<Integer,LinkedList<Node> > dist_matrix= new HashMap<Integer ,LinkedList<Node>>(2173370);
结果还是停在了2300万行的位置然后cpu到100%了,查看进程管理器,发现内存只占用了2.2G左右,但我给这个程序分配了最大6G的内存,分配的方法是:
在Debug Configuration里的(x)=Aguments的Program arguments下添加如下参数:
-Xms1024m
-Xmx6144m
-XX:PermSize=1024m
-XX:MaxPermSize=6144m
您看看是不是我分配方法有问题,我的疑问是,就算是内存不足,也不应该卡在2.2G这个地方,而是应该在6G,或者至少应该4,5G啊。thanks.
stevenyou
2014-09-01 10:10:34 +08:00
跑的时候在java opts里加个 -Xrunhprof:cpu=samples,interval=10,depth=8
程序停掉的时候目录下会多一个"java.hprof.txt", 看那里面profiler 显示哪个function 用的时间多。 这个是发现问题最容易和方法。 hprof是java 自带的profiler
stevenyou
2014-09-01 10:20:21 +08:00
还有,你用的内存都是在heap里,所以不需要设 PermSize , default size 32M or 96M based on 32bit or 64 bit is big enough
buptlee
2014-09-01 10:25:58 +08:00
是应该在program arguments下设置还是VM arguments下设置呢?
下面的参数可以吗?
-Xms1024m
-Xmx6144m
stevenyou
2014-09-01 10:33:20 +08:00
VM, 传给java的
如果你放在program arguments里, 就可以解释为什么会卡在2.3G了, jvm deault heap size 是2048m, jvm在 GC , 在3 次full GC,释放不了2%内存的话就会throw out of memory exception: excessive GC time

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/130974

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX