java - 需要 Solaris 和 Java 连续内存说明

标签 java solaris virtual-memory sunos

背景:

我们有一个供应商提供的 Java 应用程序,它有一个有点大的 Java 堆。无需介绍太多信息,该应用对我们来说就是一个黑盒子,但我们觉得我们需要自己动手尝试调整性能并解决问题。

64 位 SunOS 10 机器有 16GB 内存,唯一运行的非系统应用程序是此应用程序的 JVM。 64 位 JVM 在 JBoss 中运行,我认为这与本次讨论无关,最大堆大小为 8GB,我认为这是相关的。

最近的问题是我们遇到了各种内存不足错误。当这些错误发生时堆未满并且错误询问“交换空间不足?”。供应商希望我们将交换空间从 2GB 增加到 4GB,这是在具有 16GB 的系统上,而应用程序只有 8GB。我们认为这对性能来说不是一个好主意。

我的问题:

所以我们发现一件事是文件缓存会耗尽所有剩余的空闲内存来提高性能。通常不是问题,但它显然会使内存碎片化。由于 Hotspot JVM 需要连续的内存空间,我们了解到这种内存碎片会导致使用未碎片化的交换空间。

但是,我不确定我是否理解了碎片与连续内存要求之间的关系。当然,碎片只是指物理内存的碎片。使用虚拟内存,完全有可能分配一个连续的 ram block ,而无需由连续的 ram block 支持。换句话说,一个不连续的物理内存块对于正在运行的进程来说就像一个连续的虚拟内存块。

所以,我想,那里没有单句问题,但是有人对这个主题了解更多并且可以插话吗?有任何链接提到 64 位系统上的这个连续内存问题吗?

到目前为止我发现了什么:

到目前为止,我发现的每一个关于“连续内存”问题的引用文献都更多地与虚拟地址空间在 32 位地址系统中的布局方式相关。由于我们运行的是 64 位系统(我认为具有 48 位寻址),因此有充足的虚拟地址空间来分配大的连续 block 。

我一直在整个互联网上寻找这些信息,但到目前为止,我一直无法找到我正在寻找的信息。

更新:

  • 需要明确的是,我并不是要回答为什么会出现 OOM 错误,而是要了解可能存在碎片化的系统 RAM 与 java 所需的连续虚拟内存块之间的关系。
  • prstat -Z

ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE  
     0       75 4270M 3855M    24%  92:24:03 0.3% global

  • 回声“::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 大小以允许这 8 GB 立即可用JVM,而不是依赖于操作系统正在做的 self 调整,目前可能会被过小的交换混淆。查看Limiting the ARC cache chapter in the ZFS evil tuning guide有关如何执行此操作的详细信息。

关于java - 需要 Solaris 和 Java 连续内存说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9500542/

相关文章:

unix - 在Solaris的哪里设置LD_LIBRARY_PATH?

python - 如何删除 python disutils 包含的编译器选项(无法识别语言代码=pic32)

c++ - 访问未分配的页面

java - 如何使 IntelliJ Idea 仅显示编译器生成的警告并抑制智能检查?

linux - ksh:将函数输出分配给数组

java - 使用 Spring MVC 和 thymeleaf 的“下一个”/“上一个”按钮更改列表中的对象

linux - pthread_create 在 Linux 中分配大量内存?

c - 链接器如何生成最终的虚拟内存地址?

Java对象添加/更新/删除算法

java - java Rest请求时偶尔出现"407 Proxy Authentication Required"错误