大家来帮我看看这个 java 内存问题吧,我快崩溃了。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
buptlee
V2EX    Java

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

  •  
  •   buptlee
    Xiaoxin2009 2014-08-31 21:53:55 +08:00 6820 次点击
    这是一个创建于 4060 天前的主题,其中的信息可能已经有所发展或是发生改变。
    程序的开始是读入一个文件里的数据,数据的格式是:
    每一行为三个字段例如:
    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程序单独分配内存的?
    拜谢各位啊。
    第 1 条附言    2014-09-01 09:34:19 +08:00
    public HashMap<Integer ,LinkedList<Node> > getDistMatrix(String fileName,HashMap<Integer,ArrayList<Integer>> clusterSet){

    HashMap<Integer,LinkedList<Node> > dist_matrix= new HashMap<Integer ,LinkedList<Node>>(2173370);
    try{
    File myFile = new File(fileName);
    FileReader reader = new FileReader(myFile);
    BufferedReader breader = new BufferedReader(reader);

    System.out.println("start to load the distance matrix to memory . ");
    String line = null;
    int index = 0;
    LinkedList<Node> top50 = null;
    int userA = -1;
    while((line = breader.readLine())!=null){
    if(index%1000000==0){
    System.out.println("have loading "+index+" lines .");
    }
    if(index%50 == 0){
    top50 = new LinkedList<Node>();
    String [] tokens = line.split(",");
    ArrayList<Integer> set = new ArrayList<Integer>();
    userA = Integer.parseInt(tokens[0]);
    set.add(userA);
    clusterSet.put(userA, set);
    }

    String [] tokens = line.split(",");
    int userB = Integer.parseInt(tokens[1]);
    int distance = Integer.parseInt(tokens[2]);
    Node node = new Node(userB,distance);
    //HashMap<Integer, LinkedList<Node>> top50;
    top50.addLast(node);
    if(index%50 == 49){
    //System.out.println("the length of top50 is : "+top50.size());
    dist_matrix.put(userA, top50);
    }
    index++;
    }

    breader.close();
    System.out.println("finish getting the distance matrix . ");
    }catch(Exception x ){x.printStackTrace();}

    return dist_matrix;
    }



    class Node implements Comparable<Node>{

    Integer imsi;
    Integer dist;

    public int compareTo(Node s){
    return dist.compareTo(s.getDist());
    }

    public Node(){
    imsi = -1;
    dist = Integer.MAX_VALUE;
    }

    public Node(Integer imsiNo,int distance){
    imsi = imsiNo;
    dist = distance;
    }

    public int getDist(){
    return dist;
    }

    public Integer getImsi(){
    return imsi;
    }

    public void setImsi(Integer _imsi){
    imsi = _imsi;
    }
    }
    21 条回复    2014-09-01 10:34:41 +08:00
    plucury
        1
    plucury  
       2014-08-31 22:22:32 +08:00   1
    怀疑是内存问题可以用jmap打印内存占用情况。但是既然cpu占用100%的话,可以考虑用jstack打印线程运行命令来看看,如果看起来没问题考虑启动时打印GC日志,看看是否有频繁的full gc
    cloud107202
        2
    cloud107202  
       2014-08-31 22:39:56 +08:00   1
    内存问题不是很了解,说点我想到的
    1. 插入过程有没有并发调用HashMap.get(),这个可能会发生死锁http://coolshell.cn/articles/9606.html
    2. 如果可能的话,考虑下redis这类内存数据库
    undeflife
        3
    undeflife  
       2014-08-31 23:15:17 +08:00   1
    如果是内存问题的话 应该会报OOM 或OOM:PermGen space的

    查查文件在2300万行左右是否有什么问题导致你在读取文件的时候卡住
    读取文件的代码会不会有什么bug引起问题
    怀疑LinkedList 的话完全可以把LinkedList换成Node[50]
    ahcat
        4
    ahcat  
       2014-08-31 23:25:15 +08:00 via iPhone   1
    换一个64位的jvm?
    buptlee
        5
    buptlee  
    OP
       2014-08-31 23:36:54 +08:00
    @ahcat 就是64bit啊。嘿嘿。
    lehui99
        6
    lehui99  
       2014-09-01 00:10:58 +08:00 via Android   1
    HashMap的内部实现是数组+链表,在key的数量扩大时有可能导致数组和所有链表的内存重新分配,并将其中所有的引用重新赋值到新的数组中并重新生成所有的链表,十分耗时。可以看一下HashMap的具体实现的详细分析: http://blog.csdn.net/blog/vking_wang/14166593 ,中的最后一段:rehash过程。
    解决方法是在HashMap初始化时指定initCap,如: new HashMap(130000000/50) 。
    akfish
        7
    akfish  
       2014-09-01 06:09:39 +08:00 via iPad   1
    数据固定么?需要改动么?改了需要写回文件么?
    既然数据格式已知,完全没必要用HashMap和LinkedList,直接分配一个巨大的Array,减少overhead。对应key的index很容易计算,或者用一个HashMap<Integer, Integer>来记录每个key的第一个index。
    另外就是一次完成分配可以提高分配到连续内存的概率,减少碎片的产生。
    nybux
        8
    nybux  
       2014-09-01 08:43:50 +08:00   1
    HashMap在构造的时候加个参数
    new HashMap<>(2400001);
    buptlee
        9
    buptlee  
    OP
       2014-09-01 09:20:19 +08:00
    @lehui99 好的,试试看。谢谢兄弟。
    stevenyou
        10
    stevenyou  
       2014-09-01 09:27:39 +08:00   2
    楼主对内存的估算不太正确, 没有算进去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
        11
    buptlee  
    OP
       2014-09-01 09:31:35 +08:00
    @cloud107202 没有并发问题,有没有redis的入门资料呢,贴个链接啥的,不太懂这个,嘿嘿。
    stevenyou
        12
    stevenyou  
       2014-09-01 09:32:21 +08:00   1
    cpu使用率后来达到了100% 应该是在rehash
    buptlee
        13
    buptlee  
    OP
       2014-09-01 09:38:19 +08:00
    @stevenyou 贴出来啦,您给看看。嘿嘿。
    stevenyou
        14
    stevenyou  
       2014-09-01 09:52:25 +08:00   2
    @buptlee 应该没什么问题, 像 @lehui99 说的在HashMap初始化时指定initCap 应该可以解决这个问题。
    建议是,如果你对内存使用在意的话,可以使用别的一些数据类型(Gnu Trove 里的TIntObjectHashMap, TIntArrayList etc. )在几乎不损失性能的同时把总内存降低到2G ~ 3G
    stevenyou
        15
    stevenyou  
       2014-09-01 09:53:13 +08:00   1
    buptlee
        16
    buptlee  
    OP
       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
        17
    stevenyou  
       2014-09-01 10:10:34 +08:00   2
    跑的时候在java opts里加个 -Xrunhprof:cpu=samples,interval=10,depth=8
    程序停掉的时候目录下会多一个"java.hprof.txt", 看那里面profiler 显示哪个function 用的时间多。 这个是发现问题最容易和方法。 hprof是java 自带的profiler
    stevenyou
        18
    stevenyou  
       2014-09-01 10:20:21 +08:00   1
    还有,你用的内存都是在heap里,所以不需要设 PermSize , default size 32M or 96M based on 32bit or 64 bit is big enough
    buptlee
        19
    buptlee  
    OP
       2014-09-01 10:25:58 +08:00
    是应该在program arguments下设置还是VM arguments下设置呢?
    下面的参数可以吗?
    -Xms1024m
    -Xmx6144m
    stevenyou
        20
    stevenyou  
       2014-09-01 10:33:20 +08:00   1
    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
    buptlee
        21
    buptlee  
    OP
       2014-09-01 10:34:41 +08:00
    @stevenyou cool! I will have a try as you say! Thanks bro.=.=
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3633 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 00:16 PVG 08:16 LAX 17:16 JFK 20:16
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86