为什么我得到堆outOfMemory异常?

时间:2014-01-26 07:48:31

标签: java jvm heap

我正在尝试分配一个大矩阵(大约10GB)。我正在使用64位JVM的64位机器。然后我的进程应该有2^64字节可用,并且我已经将JVM堆大小设置为128G(如果重要的话,我的机器中有16GB的RAM)。我的理解是我应该从操作系统获取内存,操作系统会将不需要的矩阵单元换出。但是我得到了上述例外。

编辑:

这就是我定义矩阵的方式:

Jama.Matrix A = new Matrix(num_words, num_documents);

num_words约为100k且num_documents约为35k。 另外值得一提的是,类型为double

EDIT2:

相关标志:

-Xms40m
-Xmx128g
-d64

3 个答案:

答案 0 :(得分:2)

在这方面,JVM作为本机进程工作:JVM从OS请求内存,可以在交换机的RAM中分配它。

您可以在java中分配的内存不依赖于您的RAM,而是依赖于您在运行JVM时指定的命令行选项-Xmx。如果RAM内存不足,JVM会从交换中接收它(我相信)甚至不知道。

然而,

  • 在某些操作系统(Windows XP)中,限制为4G。
  • JVM中的堆不是为了运行磁盘而设计的。
  • 交换有限。

如果您需要处理大数据,则需要使用BigMemory产品(EhCache或Terracotta)。

最后,运行jvisualvm或使用-verbose:gc参数查看堆分配。

答案 1 :(得分:1)

这里有一些描述:

Xms -> the init memory that should be allocated in the start up in MB.
Xmx -> the Max amount of memory that your application can get in MB e.g Xmx2048m.
-XX:MaxNewSize= -> the max S1 and S2 memory size
-XX:NewSize= -> init S1 and S2 size

所以在您的情况下,如果您想尽可能多地分配内存,那么您需要说明16 * 1024 = 16384 or 16g-XX:MaxNewSize= and -XX:NewSize=将其设置为Xmx的40%

答案 2 :(得分:1)

你应该知道一些事情。

  • 托管内存不能很好地交换。事实上,它通常会导致您的应用程序死亡或您的操作系统锁定(尤其是如果甚至交换了10%的堆,您还需要重启电源)
  • 堆分为多个区域,并且不会像您期望的那样始终调整大小。通常它会将这些区域缩放在一起,例如它将使年轻和终身空间1:8,即你不能轻易地立刻抓住几乎所有的堆。我会尝试192 GB的最大堆。
  • 大多数高级进程支持48位地址空间或256 TB虚拟内存,仅支持40位实际内存(每个处理器1 TB)
  • -d64仅适用于Solaris。

简而言之,您需要大约256 GB的主内存和大堆,您真正考虑的是您在做什么。随机访问内存比访问磁盘空间快一百万倍,这意味着它不仅慢一百万倍,而且根本不可能工作。

你可以做的就是使用堆内存,如果你真的知道自己在做什么,你可以做到这一点,并且可能只比你需要的内存慢100倍。 esp如果你使用快速SSD进行交换,或者你的矩阵是稀疏的,那就是正确的方法。