【问题标题】:Reducing memory usage of very large HashMap减少非常大的 HashMap 的内存使用
【发布时间】:2011-07-18 18:21:20
【问题描述】:

我有一个非常大的哈希映射(2+ 百万条目),它是通过读取 CSV 文件的内容创建的。一些信息:

  1. HashMap 将一个字符串键(小于 20 个字符)映射到一个字符串值(大约 50 个字符)。
  2. 这个 HashMap 的初始容量为 300 万,因此负载因子约为 0.66。
  3. HashMap 仅由单个操作使用,一旦该操作完成,我“clear()”它。 (虽然这种清除似乎并没有真正清除内存,但是否需要单独调用 System.gc()?)。

我的一个想法是将 HashMap 更改为 HashMap 并使用 String 的 hashCode 作为键,这最终会节省一些内存,但如果两个字符串具有相同的哈希码,则可能会出现冲突问题......如何这可能适用于长度少于 20 个字符的字符串吗?

还有其他人对在这里做什么有任何想法吗? CSV 文件本身只有 100 MB,但 java 最终为此 HashMap 使用了超过 600 MB 的内存。

谢谢!

【问题讨论】:

  • 如何使用嵌入式数据库,例如 HSQLDB 或 SQLite。 hsqldb.orgsqlite.org
  • 在需要唯一值的地方使用哈希码总是会带来麻烦。 “可能”不是问题:哈希码中根本没有足够的位来唯一地指定 20 个字符的字符串。

标签: java memory memory-management memory-leaks hashmap


【解决方案1】:

听起来你已经有框架可以尝试这个了。不要添加字符串,而是添加 string.hashCode() 并查看是否发生冲突。

在释放内存方面,JVM一般不会变小,但如果需要它会进行垃圾回收。

另外,听起来您可能有一个根本不需要哈希表的算法。您能否更详细地描述您正在尝试做的事情?

【讨论】:

  • 当然,我有一个将字符串代码映射到字符串描述的 CSV。然后我有一个单独的 CSV 文件,其中一列是代码。当我处理第二个 CSV 文件时,我需要使用描述而不是代码。这就是生成的 HashMap 发挥作用的地方。一旦该操作完成,就不再需要从代码->描述的映射。
  • 一个想法:如果您的第二个文件没有使用第一个文件中的所有代码,则首先解析该文件并仅使用您知道您需要的代码加载您的哈希表。这是文件的额外运行,但如果您只需要加载第一个文件的一小部分,则可能值得。
  • 另一个想法,如果您可以以不同的顺序处理您的第二个文件,则按 ID 对第一个和第二个文件进行排序。然后您可以遍历第一个文件,直到在第二个文件中看到您尚未处理的 ID;停止处理第二个文件中的所有这些 ID,然后继续处理第一个文件中的下一个 ID。这样您就不必在内存中存储 任何内容,但需要先以合理的顺序对文件进行排序。
【解决方案2】:

解析 CSV,并构建一个 Map,其键是您现有的键,但值是指向该键在文件中位置的整数指针。

当您想要某个键的值时,请在映射中找到索引,然后使用 RandomAccessFile 从文件中读取该行。在处理过程中保持 RandomAccessFile 打开,完成后关闭它。

【讨论】:

    【解决方案3】:

    您正在尝试做的正是一个 JOIN 操作。尝试考虑像 H2 这样的内存数据库,您可以通过将两个 CSV 文件加载到临时表然后对它们执行 JOIN 来实现这一点。 根据我的经验,h2 在加载操作方面运行良好,并且此代码肯定会比您基于手动 HashMap 的加入方法更快且内存占用更少。

    【讨论】:

      【解决方案4】:

      如果性能不是主要考虑因素,请将条目存储在数据库中。那么内存就不是问题了,而且你有很好的搜索速度,如果不是很好,多亏了数据库。

      【讨论】:

      • 假设数据库不可行,使用内存数据库是否可行?我认为它可能比使用标准 java HashMap 有一些优化。
      猜你喜欢
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      • 2013-05-21
      • 2022-08-23
      相关资源
      最近更新 更多