所以,我正在运行一个java服务器(特别是Winstone:http://winstone.sourceforge.net/)
像这样: java -server -Xmx12288M -jar /usr/share/java/winstone-0.9.10.jar --useSavedSessions = false --webappsDir = / var / servlets --commonLibFolder = / usr / share / java
过去这种方法运行良好,但现在需要将更多内容加载到内存中。
奇怪的是,根据'top',它有15.0g的VIRT(ual内存),而它的RES(识别集)是8.4g。一旦达到8.4g,CPU就会挂起100%(即使它是从磁盘加载的),最终,我得到了Java的OutOfMemoryError。据推测,CPU挂起100%是Java正在进行垃圾收集。
所以,我的问题是,是什么给出的?我给了它12个演唱会!并且只有在它投入之前才使用8.2演出。我做错了什么?
哦,我正在使用 java版“1.6.0_07” Java(TM)SE运行时环境(版本1.6.0_07-b06) Java HotSpot(TM)64位服务器VM(版本10.0-b23,混合模式)
在Linux上。
谢谢, 马特
答案 0 :(得分:8)
奇怪的是,根据'top',它有15.0g的VIRT(ual内存),而它的RES(识别集)是8.4g。一旦达到8.4g,CPU就会挂起100%(即使是从磁盘加载),最终我得到了Java的OutOfMemoryError。
我认为你误解了一些事情。 “-Xmx12288M”选项不保留物理内存。而是设置Java堆大小的上限。 Java还需要非堆对象的内存;例如permgen空间,代码空间,内存映射文件等。 对于12g堆+ JVM使用/共享的非堆内存来说,最多可以添加15g。
top报告为RES的8.4g是当前用于运行JVM的物理内存量。它与Java堆的大小没有直接关系。实际上,当操作系统虚拟内存系统交换不同进程的页面时,您会期望RES编号上下移动。这完全不受JVM的控制。
据推测,CPU挂起100%是Java正在进行垃圾收集。
是。这通常会发生什么。
我可以想到三种可能的解释:
最有可能的是,操作系统无法为您的JVM提供所要求的内存,因为没有足够的交换磁盘空间。例如,如果你有2个进程,每个进程有15g的虚拟内存,那就是30gb。鉴于您有24g物理内存,您将需要至少8g(可能更多)的交换空间。如果可分配给用户进程的物理内存量+交换空间量小于进程使用的总虚拟空间,则OS将开始拒绝JVM扩展堆的请求。您可以运行“swapon -s”以查看可用/正在使用的交换空间。
您的应用程序可能确实正在使用您已声明可以使用的所有12g堆,这还不够。 (也许你有一个存储泄漏。也许它真的需要更多的内存。)
也有可能(但极不可能)有人设定了流程限制。您可以使用shell builtin'ulimit'命令查看是否已完成此操作;有关详细信息,请参阅“man ulimit”。
编辑
如果您使用-verbose:gc
和-XX:+PrintGCDetails
选项,GC可能会为您提供更多有关正在发生的事情的线索。特别是,它会告诉你内存不足时Java堆的大小。
您可以编写一个简单分配并且不会释放大量内存的Java应用程序,并查看在使用与您当前相同的选项运行时因OOM错误而导致分配的数量。使用。 (我认为这不会告诉你任何新内容。编辑2 实际上,如果你以@Dan建议的方式运行它,会告诉你一些事情!)< / p>
如果(似乎很可能)真正的问题是你没有足够的交换空间,那么在Java方面你无法做任何事情来解决这个问题。您需要重新配置系统以获得更多的交换空间。请参阅Linux系统管理文档,man
,swapon
等mkswap
页面。
答案 1 :(得分:1)
有时OutOfMemorError并不意味着对象堆已用完 - 而是其他东西。错误堆栈上还有其他信息吗?
特别是,JVM需要一堆与堆空间分开的内存/地址空间。在某些时候,为进程提供更多的对象堆可以为这个其他池留下更少的空间 - 矛盾的是,使用更大的'-Xmx'设置更有可能使OOME成为可能!
内存映射文件会占用大量地址空间;如果无法正确关闭文件,可以将此空间分配到GC / finalization,这将在不可预测的时间发生。此外,拥有更大的堆会导致GC /终结 - 这意味着此本机地址空间可能会保留更长时间,因此:更大的堆可能意味着由于耗尽其他内存而更频繁的OOME。
您还可以使用相同值的'-Xms'强制在启动时立即抓取所有堆地址空间 - 可能会在更方便/可理解/可重现的阶段触发失败。
最后,即使没有内存请求失败,也会有一个OOME被抛出的阈值 - 但GC正在“花费太多”时间,表明垃圾的创建速度与收集时一样快,可能是在一个紧密的循环中。磁盘上的低效负载会为少量保留的数据创建大量垃圾,这可能会导致这种情况。查找[GC开销限制]以获取详细信息。
答案 2 :(得分:0)
您可以升级到最新版本的java(1.6.0_17)吗?
答案 3 :(得分:0)
也许是一个愚蠢的问题,但你确定你的交换分区在程序启动时至少有15GB可用空间吗?
答案 4 :(得分:0)
而且要确认一下,PermGen空间不是正确的吗?
答案 5 :(得分:0)
奇怪的是,根据 “顶部”,它有15.0克的VIRT(ual 记忆)它的RES(识别集)是 8.4克。一旦达到8.4g,CPU就会挂起100%(即使它正在加载 磁盘),最终,我得到了Java OutOfMemoryError异常。想必是CPU 挂在100%是Java做垃圾 集合。
我猜想java必须使用它决定(或被迫)为你的数据使用磁盘空间的那么多内存。现在下次它必须收集垃圾时,必须使用IO来执行此操作。在磁盘上进行垃圾收集肯定是相当昂贵的。而且因为你有那么多的对象,垃圾收集器可能会一次又一次地跳进去。这可能就是为什么你的CPU处于100%......永远做垃圾收集的原因。
正如Stephen所说 -verbose:gc 和 -XX:+ PrintGCDetails 会给出更多提示。
但除此之外,投资一个不能同时加载所有文件的实现可能会付出代价吗?在记忆极限下工作看起来不像是一个成功的策略。