由于未释放Linux RAM磁盘缓存,导致Java OutOfMemoryError

由于未释放Linux RAM磁盘缓存,导致Java OutOfMemoryError,java,linux,memory,linux-kernel,Java,Linux,Memory,Linux Kernel,进程将整天正常运行,然后,bam,在没有警告的情况下,它将抛出此错误。有时似乎在无所事事的中间。它将在一天中看似随机的时间发生。我检查了机器上是否还有其他东西在运行,比如定时备份之类的,但什么也没找到。机器有足够的物理内存(2GB,对于3-500MB的负载大约有1GB的可用内存),并且有足够的指定的-Xmx 根据我们的系统管理员的说法,问题在于当JVM需要分配内存时,内核用作磁盘缓存(显然除了8MB之外)的RAM没有被释放,因此JVM进程抛出OutOfMemoryError。这可能是因为Java

进程将整天正常运行,然后,bam,在没有警告的情况下,它将抛出此错误。有时似乎在无所事事的中间。它将在一天中看似随机的时间发生。我检查了机器上是否还有其他东西在运行,比如定时备份之类的,但什么也没找到。机器有足够的物理内存(2GB,对于3-500MB的负载大约有1GB的可用内存),并且有足够的指定的-Xmx

根据我们的系统管理员的说法,问题在于当JVM需要分配内存时,内核用作磁盘缓存(显然除了8MB之外)的RAM没有被释放,因此JVM进程抛出OutOfMemoryError。这可能是因为Java在分配内存之前询问内核是否有足够的内存可用,并发现内存不足,导致崩溃

然而,我想,Java只是试图通过内核分配内存,当内核收到这样的请求时,它通过抛出一些磁盘缓存为应用程序腾出空间

有没有其他人遇到过这个问题?如果有,错误是什么?您是如何解决的?
我们目前正在VMWare ESX中的SLES 10 SP2 Linux 2.6.16.60-0.42.9-smp上使用jdk1.6.020。

您知道在引发该异常时java分配了多少内存吗?问题可能是Java使用了-Xmx指定的所有内存。(请记住,-Mmx提供了允许的最大内存使用量,因此,如果使用量超过指定大小,java将抛出OutOfMemoryException,即使linux内核能够为其提供更多内存)

但要确定是否是这种情况,请尝试将-Xms设置为与-Xms指定的大小相等的-Xms。(-Ms设置初始大小,java应该低于此值,因此它将在启动时分配所有需要的内存)

如果java仍然启动,并且仍然给您OutOfMemoryException,那么问题很可能是您的-Mx太小了

ps:我非常确定,对于普通的linux内核,内存分配不会失败,因为内核会过度分配内存,所以如果整个系统的内存确实不足,那么会出现页面错误(oom杀手会杀死一个任务),而不是java异常。但是java可能会使用一些特殊的特性来分配内存,所以我不确定这是否适用于这里

根据我们的系统管理员的说法,问题在于当JVM需要分配内存时,内核用作磁盘缓存(显然除了8MB之外)的RAM没有被释放,因此JVM进程抛出OutOfMemoryError

我想你的系统管理员搞错了。Linux将根据系统运行进程对物理内存的需求,自动、透明地增加和缩小缓冲区缓存的大小。如果没有,那么你的操作系统就严重损坏了

Java应用程序更有可能出现内存泄漏,导致其使用的堆空间量稳步增加。最终,您会遇到-Xmx限制并得到一个OOME。我将通过在启用GC日志记录的情况下运行应用程序来开始研究这个问题。这将告诉您堆是如何随时间增长的,GC回收了多少空间等等


另一种可能是您没有配置足够的交换空间。

您是否分配了大量内存?比如说,一个100 MB长的[]阵列?然后我不确定,但您可以尝试将使用的最小内存量固定为最大内存量,仅用于测试:-Xms1500M-Xmx1500m这可能会给您的系统管理员一些实验的食物。不是这样的,不是。我处理XML消息,并从数据库读取和写入数据。非常简单的东西。XML消息很少超过几KB。你有没有发现这个问题?我有一个数组,显示每个节点都有大约20GB的缓存内存,但是java服务不断出现堆问题。它至今仍是一个谜…我确实有2GB的交换空间,但java拒绝接触它。当我耗尽物理内存时,即使没有使用交换,java也会抛出OOME。我也不认为内核磁盘缓存是罪魁祸首,但我认为我应该提供到目前为止获得的所有信息。我认为你应该在ServerFault上问这个问题。听起来可能是某种VMware配置。(可能您的虚拟机不知道它有一张交换光盘?您需要调用
swapon
或虚拟机启动时的其他功能吗?)