【问题标题】:Working with Huge ArrayLists, Java OutOfMemoryError: Java heap space... use db?使用巨大的 ArrayLists,Java OutOfMemoryError: Java heap space... 使用 db?
【发布时间】:2011-06-07 09:53:39
【问题描述】:

我有一个内存问题,我完全理解原因,但不知道如何解决。我尝试使用 -Xmx2g 标记并使堆大小变大,但似乎有一个隐藏的最大值。 (如果我使用 -Xmx512m 我会同时用完空间)。

假设我有 2 个对象,一个区域和一个用户。我的 Area 对象包含用户的 ArrayList:

public class Area {
      int numUsers;
      ArrayList<User> userList;
}

我的 User 类拥有一个朋友的 ArrayList:

public class User {
      int userID;
      int numFriends;
      ArrayList<User> friends;
}

仅使用单个区域,有 100 万用户,每个用户平均有 200 个朋友,在创建大约 680,000 个用户后,我用完了堆空间。显然,如果我将朋友/用户的平均数量降低到接近 100,我可以将所有这些对象存储在堆中。

如果我想模拟一个区域内的 200 万用户怎么办?还是数百个地区的?

有了这么多数据,数据库是使用这些信息进行模拟的唯一可行方法吗?

【问题讨论】:

  • 是的,将这种大小的图表放入单个 VM 会变得很拥挤。不,除了关系数据库之外,还有很多方法可以保存和处理这么多数据。哪种方式适合您的情况取决于您要对数据做什么,以及您的性能要求是什么。您甚至可以根据需要创建数据,而无需将其完整存储?
  • 完整存储它的需要是最终有多个区域,其中区域 1 的一些用户可以有区域 42 的朋友。我想那时将它存储在内存中不会是一种选择.在这一点上,我只需要对这些信息进行建模。该项目需要一个现实的社交网络模型。有什么我应该研究的结构,你知道吗?
  • 存储在内存中可以走很远。目前的内存定价为 100 欧元/8GByte,大多数系统不应基于磁盘。

标签: java database memory-management out-of-memory heap-memory


【解决方案1】:

只有在您能够承受 100.000 倍的随机访问性能损失时,磁盘/数据库才是一种解决方案(您可能会有很多系统使用数据库)。您可以使用专门的数据结构做得更好。为完全连接的子网做一些特殊的事情可能会节省很多空间。

【讨论】:

  • Hhhmm... 任何指向您所说的结构的链接?非常感谢。
  • 只需添加一个包含用户 ArrayList 的 FullyConnectedSubset 类,并让朋友多态?
  • 我不太清楚你的意思。我想你是在朋友级别谈论。因此,拥有 100 个朋友的用户将与这些朋友中的每一个相关联,但这并不能帮助我将其放入记忆中。让朋友扩展用户会更好吗?不确定如何节省空间,因为现在朋友是用户。 ArrayList 好友;
  • 在全连接子集中,每个朋友都相互连接。与其将其存储为 n 个朋友中的 n-1 个条目的列表,不如创建一个特殊元素:FullyConnectedSubset,将其添加到这 n 个朋友中。取 O(n) 而不是 O(n^2) 空间。然后你必须创建一些访问器/迭代器来隐藏这个实现细节。
【解决方案2】:

当然,您可以在 64 位 java 上运行超过 2m 的文件,但这并不能解决问题。顺便说一句,对于Area,你可能需要id(不是numUsers),用户/朋友的数量可以从list.size()中获得

数据库/磁盘存储是表示大量对象的自然解决方案,您可以选择使用服务器集群(除了运行一个带有 500+GB 内存的大盒子)

要回答这个问题,您必须提供更多数据:区域/朋友图等的意义何在。


如果您可以使用 ByteBuffer 编写自己的 struct(ure)(这可能不是一件容易的事),那么您可以超越 java.io.MappedByteBuffer、ScatteringByteChannel/GatheringByteChannel 的 32 位限制。但是,无论如何这不是一个新手任务,但如果您喜欢编程,我建议您尝试一下。

祝你学习顺利。

【讨论】:

  • 区域创建前实际传入的用户数。这样,当我创建具有不同数量用户的多个区域时,我可以做到这一点。每个用户都有自己的 id。这是一个用于创建逼真的社交网络模型的学校项目。
  • 您的图模型有一个主要缺点,如果您依赖 ArrayList,它将缺少任何类型的实际搜索/跟踪方法。 ArrayList 需要 O(n) 才能进行简单的包含操作。其他几点注意事项:确保每个实体只有一个 User 实例(我假设 userID 定义了一个身份)
  • 调用 trimToSize() 或确保使用带有 initialCapacity 的构造函数以避免过多的字节进入 Object[]。 _____ 底线:如果您需要大内存,请使用 64 位操作系统
  • 我知道当/如果进行逼真的模拟时,该结构不会有效。我希望在内存中创建数据,然后将其转储到更适合进行模拟的结构中。即使这超出了项目的范围。
  • 将其创建为外部形式(因为如果您想用于真实,则需要公开您的结构)可以做到这一点。 (谈MappedByteBuffer)
【解决方案3】:

要访问更多堆内存,请移至 64 位操作系统和 64 位 JVM。如果您在使用 -Xmx512m 时遇到问题,则说明您使用的是 32 位操作系统和/或 JVM。

【讨论】:

  • 我正在使用 Fedora c14 32 位。我最多有 256 个?
  • 实际的最大值取决于许多复杂的问题,例如库的内存映射以及如何分割内存空间。通过确保使用 java 可执行文件而不是链接库(不确定在 linux 上调用什么库)来启动 java,您可能可以获得更多可用的内存空间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 2014-01-05
  • 2020-11-16
相关资源
最近更新 更多