0

我的程序需要向数据容器中插入超过数百万条记录。我尝试了 hashmaptreemap。尽管我允许JVM 使用 2gb ram,但两者都会给我堆空间异常。

我的程序经常从容器中获取特定数据,我认为如果需要 O(logn) 时间,我可以接受。那么我应该使用什么容器呢?或者我需要实施一个?如何?

更多细节:键是字符串,就像一个全局ID,例如“00011123459”之类的。然后键将映射到列表列表,即List<List<String>>。我的程序从文件中读取行,然后将行更改为列表,然后从列表中获取全局ID,然后将列表放入相应的列表列表中。该文件有超过数百万行,这就是为什么我认为主要原因是我创建了太多列表。但是,我无法向机器添加更多内存。

4

4 回答 4

1

HashMap 比 a占用更少的内存TreeMap并且是 O(1)。

如果您的键是数字,您可以使用TLongObjectHashMapTrove4j 节省内存。

另一种选择是使用MapDB将数据临时保存在磁盘上。

CacheBuilder您还可以在 Guava 中应用缓存:当 Java 中的集合超出容量时会发生什么?

于 2013-10-28T10:09:54.890 回答
1

假设绝大多数内存使用是由于记录数据本身造成的,可能没有选择容器可以解决您的问题(作为测试,尝试将所有数据加载到数组中;如果您用完内存,你需要另一种解决方案)。不仅如此,如果您将其削减到接近容量,如果您将来遇到大量记录,您仍然会遇到问题。

除了添加更多 RAM,您还可以采取许多其他方法,但总体思路是在磁盘上存储更多,在内存上存储更少。以下是一些可能的替代方案:

  • 将您的记录存储在适当的数据库中(这里有很多选项,SQLite 可能对您来说最方便——也有很多访问选项,从直接java.sql.*到 Hibernate)。
  • 正如 Andrey Chaschev 提到的,使用类似MapDB的东西。
  • 如果您的程序经常访问一小部分数据,或者连续访问相同的数据,请考虑将记录留在磁盘上,在需要时找到它们,并在找到时缓存它们(如果感兴趣的记录不在缓存中,则仅在磁盘上搜索)。
  • 与其将整个记录存储在地图中,不如存储一些信息来帮助您更快地在磁盘上找到它们并根据需要延迟加载记录(例如,将记录数据的文件偏移存储在地图中,然后在查找时从文件,如果需要,实现缓存)。

就个人而言,我会选择第一个选项(确保在您通常用于查找记录的键上创建一个索引),因为它的设置和使用非常简单,并且 SQLite(例如)是独立的并且需要没有服务器。以增加开发复杂性为代价,如果你发现你的性能要求没有得到满足,你仍然可以缓存数据,或者像 Hibernate 这样的东西会为你做。

于 2013-10-28T10:31:02.343 回答
0

javadoc

This implementation provides guaranteed log(n) time cost for 
the containsKey, get, put and remove operations.

所以使用 TreeMap 并给 Java 更多内存。

于 2013-10-28T09:28:47.823 回答
0

如果您有更多的基础架构支持,请尝试将内存增加到 4 或 5 GB 并使用这些映射中的任何一个

  1. 使用树形图 - 如果您希望对对象进行排序。由于对象已排序,因此在插入新对象后需要额外的时间来对整个地图进行排序。

  2. 使用哈希映射 - 用于快速添加/检索,因为对象未排序。

于 2013-10-28T09:34:19.087 回答