背景:
我们有一个供应商提供的Java应用程序,它有一个很大的Java堆。在不了解太多信息的情况下,该应用程序对我们来说是一个黑匣子,但我们觉得我们需要自己调整性能并解决问题。
64位的SunOS 10机器有16GB的内存,唯一正在运行的非系统应用程序是该应用程序的JVM。64位JVM运行在JBoss中,我认为这与本讨论无关,最大堆大小为8GB,我认为是相关的。
最近的问题是我们出现了各种内存不足的错误。当出现这些错误时,堆未满,并且错误询问"交换空间不足?"。供应商希望我们将交换从2GB增加到4GB,这是在一个16GB的系统上,而应用程序只有8GB。我们觉得这对表演来说是个坏主意。
我的问题:
因此,我们发现的一件事是,文件缓存会耗尽所有剩余的可用内存来提高性能。通常情况下这不是问题,但它显然会破坏记忆。由于Hotspot JVM需要连续的内存空间,我们已经了解到,这种内存碎片会导致使用未碎片化的交换空间。
然而,我不确定我是否理解碎片和连续内存需求之间的关系。毫无疑问,碎片化只是指物理ram的碎片化。有了虚拟内存,完全可以分配一个连续的ram块,而不会被连续的ram组块支持。换句话说,物理内存的非连续块对于正在运行的进程来说将表现为虚拟内存的连续块。
所以,我想,里面没有一句话的问题,但有人知道更多关于这个主题的知识并能插话吗?是否有任何链接涉及64位系统上的此连续内存问题?
到目前为止我发现了什么:
到目前为止,我发现的每一个关于"连续内存"问题的参考都更多地与32位地址系统中的虚拟地址空间布局有关。当我们运行64位系统(我认为是48位寻址)时,有大量的虚拟地址空间来分配大的连续块。
我一直在互联网上寻找这些信息,但到目前为止,我还找不到我想要的信息。
更新:
- 需要明确的是,我并不是想知道为什么会出现OOM错误,而是想了解可能碎片化的系统RAM和java所需的连续虚拟内存之间的关系
- prstat-Z
ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE
0 75 4270M 3855M 24% 92:24:03 0.3% global
- echo"::memstat"|mdb-k
Page Summary Pages MB %Tot
------------ ---------------- ---------------- ----
Kernel 326177 2548 16%
ZFS File Data 980558 7660 48%
Anon 561287 4385 27%
Exec and libs 12196 95 1%
Page cache 17849 139 1%
Free (cachelist) 4023 31 0%
Free (freelist) 156064 1219 8%
Total 2058154 16079
Physical 2042090 15953
我以前认为ZFS文件数据是免费可用的内存,但后来我了解到事实并非如此,很可能是错误的原因。
vmstat 5 5
kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr vc vc vc -- in sy cs us sy id
0 0 0 2161320 2831768 12 55 0 0 0 0 0 3 4 -0 0 1089 1320 1048 1 1 98
0 0 0 819720 1505856 0 14 0 0 0 0 0 4 0 0 0 1189 748 1307 1 0 99
0 0 0 819456 1505648 0 1 0 0 0 0 0 0 0 0 0 1024 729 1108 0 0 99
0 0 0 819456 1505648 0 1 0 0 0 0 0 0 0 0 0 879 648 899 0 0 99
0 0 0 819416 1505608 0 1 0 0 0 0 0 0 3 0 0 1000 688 1055 0 0 99
这些命令输出是在应用程序以正常状态运行时获取的。我们现在正在监视以上所有内容,并将其记录下来,以防再次看到交换空间错误。
以下是JVM增长到8GB后重新启动的情况。这样做的效果是ZFS ARC已经缩小(到26%的RAM),直到它再次增长。现在情况如何?
vmstat 5 5
kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr vc vc -- -- in sy cs us sy id
0 0 0 1372568 2749528 11 41 0 0 0 0 0 2 3 0 0 713 418 539 0 0 99
0 0 0 3836576 4648888 140 228 0 0 0 0 0 0 0 0 0 1178 5344 1117 3 2 95
0 0 0 3840448 4653744 16 45 0 0 0 0 0 0 0 0 0 1070 1013 952 1 3 96
0 0 0 3839168 4652720 6 53 0 0 0 0 0 0 0 0 0 564 575 313 0 6 93
0 0 0 3840208 4653752 7 68 0 0 0 0 0 3 0 0 0 1284 1014 1264 1 1 98
- 交换-s
总计:分配4341344k字节+保留675384k=使用5016728k,可用 3840880k
当错误消息表明交换空间可能不够大时,我通常会信任它,并显著增加交换大小。
我建议你先做,最多4 GB,甚至8 GB,看看会发生什么。扩大互换对性能没有任何影响。这是一个常见的误解。影响性能的是缺少RAM,而不是太大的交换区域。
只有在更改后问题仍然存在的情况下,我才会尝试研究其他轨道,比如内存碎片轨道。
编辑:
从您的memstat、prstat和vmstat输出中可以清楚地看到,您的系统虚拟内存不足。绝对没有必要调查其他不寻常的原因,比如内存碎片。您的可用RAM(~1.5G)比可用虚拟内存(~800MB)多。这意味着有很多未使用(尚未)的内存保留。同样,只需添加一些交换空间即可解决此问题。这不会对性能产生任何影响,因为您有足够的RAM。
编辑:(第2部分)
现在我们知道您正在使用ZFS,因为您的应用程序最多可以使用8 GB(如果考虑到非堆内存,则会使用更多),因此您应该减少最大ARC大小,以允许JVM立即使用这8 GB,而不是依赖于操作系统正在进行的自调整,而这可能会被尺寸过小的交换所混淆。有关如何做到这一点的详细信息,请参阅ZFS邪恶调优指南中的"限制ARC缓存"一章。
如果主+交换空间用完,可能会出现此错误。虽然现在2 GB的交换空间非常小,但如果您必须使用交换空间,您确实会遇到性能问题,因为这意味着您将强制应用程序交换到磁盘。
在这种情况下,增加最大堆并没有帮助,因为问题是内存不足。这甚至可能使它更有可能发生。
解决方案可能是使用更少的内存(通过减少系统上运行的其他应用程序)或增加主内存(现在16GB对于服务器来说不算多,我的家用电脑有24;)
编辑:我看到的导致这个问题的另一件事是大量使用堆内存的直接内存。例如,默认情况下,您的最大直接内存与您的最大堆大小相同。这意味着在使用所有堆之前,您的应用程序可能会使用几乎8GB的直接内存。应用程序可能会发现操作系统没有足够的主+交换空间来向堆分配内存,并且可能会死亡。
我倾向于尽可能多地使用直接内存,但这样做是为了避免使用太多堆。)