熟悉 java 内存机制的同学们来帮我瞅瞅我的内存问题吧。

2015-01-12 17:07:14 +08:00
 buptlee

我的程序要读入一个数据文件,文件的每一行是这样的:
[1001,0.0,2.846335314101648,0.2385266331350405,0.6889106550987336,0.6265634872937542,0.7916442990777731...]

每一行是由逗号分隔的11063个字段,我把读到的每一个字段转换成了float类型。每一行存到一个 ArrayList<Float>里面,一共是11063行,也就是说我存下了一个11063*11063的矩阵,矩阵的每个元素是float类型,所以总的大小应该是11063*11063*4/(1024*1024)=466M

程序读入到1万行的时候就卡住了,查看任务管理器显示内存占用量是3.4G,并且还发生了一个小插曲,当读到4000行的时候卡了20秒,按我的理解可能是在这里数组重新申请了内存,可是有有点疑惑,因为我在程序的最开始是初始化了K_L数组的:
ArrayList<ArrayList<Float>> K_L = new ArrayList<ArrayList<Float>>(12000);

按理来说不会发生类似于rehash这种动作的啊。这只是一个小插曲,我的问题是,为什么计算得到的内存是466M,而实际上用了3.4G都没有读完,并且最后停在了10000行处,就算是有额外的开销,也不至于这么大啊。我的程序非常简单,在数据结构和算法上应该是不能更精简了。我想问问同学们关于我的内存问题。还有就是大家在将这种较大的数据读入到内存中时,有什么好的方案吗,比如redis?我不太了解,只是听人提起过。大家分享下吧,thanks。代码如下。

String each_line = null;
    while((each_line = K_L_file_handler.readLine())!=null){
        String tokens [] = each_line.split(",");
        ArrayList<Float> K_L_item = new ArrayList<Float>();
        for(int i = 0 ; i < tokens.length ; i++){ 
            K_L_item.add( Float.parseFloat(tokens[i]));
        }
        K_L.add(K_L_item);
        }
    System.out.println("finish initialing the  Kullback–Leibler divergence");
3567 次点击
所在节点    程序员
25 条回复
wudikua
2015-01-13 14:08:15 +08:00
你想想为什么array list可以不用管数组的下标限制直接可以无限的add而不抛出out of bound就知道了
icespace
2015-01-14 10:18:01 +08:00
@buptlee MappedByteBuffer , 即利用file chanel(NIO)将文件部分或全部映射到内存中,用来处理大文件。这样,你就可以利用操作系统的功能来间接操作文件,而且避免了文件操作错误。需要注意的是,如果处理4G以上的大文件,你需要使用64位JVM来运行。卤煮请移步http://www.linuxidc.com/Linux/2013-11/92895.htm 。所以这个基本上就是你要的。
icespace
2015-01-14 10:23:06 +08:00
@buptlee 另外的一个思路是使用嵌入型数据库,将文件结构化的导入嵌入型数据库后,数据的存储与缓存就交由它来处理,典型的如BerkeleyDB。这个办法比内存映射文件更加有效是因为你的数据是结构化的,这样你就可以充分利用数据的排序、查找、过滤,其处理速度将会远远超过你自己写代码,而且极大减少debug的时间。你不在需要自己组织庞大的数组结构,也不在需要自己去hash。我想唯一的缺点可能就是程序包会稍微大一点。卤煮,我给你的这两条建议,你还满意么?
buptlee
2015-01-14 21:58:41 +08:00
满意到哭啊,多谢大神。
目前在钻研第一个思路。
第二个思路感觉有点复杂,先不尝试了。
thanks so much
icespace
2015-01-15 14:19:43 +08:00
@buptlee 我建议你使用第二个思路,第一个虽然解决了文件加载的问题,但是你仍然要在内存中构建巨大的数据结构,实际上并未解决问题的根源。我建议你用第二个,嵌入型数据库不用安装配置,使用同一个jvm,因此相当简单,而且数据库的使用应该是最常用的场景。

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

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

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

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

© 2021 V2EX