在java中加载大型文本文件的最佳方法

use*_*557 3 java memory string

我有一个文本文件,每行有一个整数序列:

47202 1457 51821 59788 
49330 98706 36031 16399 1465
...
Run Code Online (Sandbox Code Playgroud)

该文件有300万行这种格式.我必须将此文件加载到内存中并从中提取5-gram并对其进行一些统计.我确实有内存限制(8GB RAM).我试图最小化我创建的对象的数量(只有1个类,包含6个浮点变量,以及一些方法).并且该文件的每一行基本上生成该类的对象数(与#ofwords中的行的大小成比例).当C++出现时,我开始觉得Java不是一个很好的方法来做这些事情.

编辑:假设每行产生该类的(n-1)个对象.其中n是该行中由空格分隔的标记数(即1457).因此,考虑到每行10个字的平均大小,每条线平均映射到9个对象.所以,会有9*3*10 ^ 6个对象.所以,所需的内存是:9*3*10 ^ 6*(8字节obj标题+ 6 x 4字节浮点数)+(一个map(字符串,对象)和另一个映射(Integer,ArrayList(Objects))).我需要将所有内容保存在内存中,因为之后会发生一些数学优化.

rad*_*dai 14

读取/解析文件:

处理大文件的最佳方式,在任何一种语言,是尽量不把它们加载到内存中.

在java中,看看MappedByteBuffer.它允许您将文件映射到进程内存并访问其内容,而无需将整个内容加载到堆中.

您也可以尝试逐行读取文件并在读取后丢弃每一行 - 再次避免将整个文件同时保存在内存中.

处理生成的对象

对于处理解析时生成的对象,有以下几种选择:

  1. 与文件本身相同 - 如果您可以执行任何想要执行的操作而不将所有内容保留在内存中(同时"流式传输"文件) - 这是最佳解决方案.你没有描述你试图解决的问题,所以我不知道这是否可能.

  2. 压缩某种 - 从Wrapper对象(Float)切换到基元(float),使用类似flyweight模式的东西将数据存储在巨型float []数组中,只构造短期对象来访问它,在你的中找到一些模式允许您更紧凑地存储数据的数据

  3. 缓存/卸载 - 如果您的数据仍然不适合内存"将其分页"到磁盘.这可以简单到扩展guava到页面到磁盘或引入像ehcache或类似的库.

特别是关于java集合和地图的注释

对于小型对象,特别是java集合和映射会导致大量内存损失(主要是因为所有内容都被包装为对象以及Map.Entry内部类实例的存在).如果内存消耗是一个问题,那么你应该看看gnu trove集合.

  • 好吧,他从来没有说过它不合适.我想知道这可能只是一个过早优化的情况. (2认同)