问题描述
我有一个存在内存问题的 Java 应用程序(在 OpenJDK 1.8.0_181 下运行)。特别是在一段时间后,所有物理内存似乎都被消耗了,应用程序无法分配更多内存。困难的部分是导致问题的不是堆内存。我正在努力理解如何进一步调查它,因为它不是堆内存。
以下是我遇到的内存崩溃类型:
Exception in thread "eXistThread-22" java.lang.OutOfMemoryError: unable to create new native thread
或
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000773200000,142606336,0) Failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) Failed to map 142606336 bytes for committing reserved memory.
在所有这些情况下,服务器的物理内存都被完全消耗掉了。然后应用无法分配内存或扩展堆,从而崩溃。
首先是 top
命令的结果:
KiB Mem : 7867456 total,454608 free,6696500 used,716348 buff/cache
KiB Swap: 0 total,0 free,0 used. 933392 avail Mem
PID USER PR NI VIRT RES SHR S %cpu %MEM TIME+ COMMAND
18 root 20 0 8827048 6.180g 28028 S 0.0 82.4 24:41.10 java
Java 应用程序正在使用以下内存设置运行:java -xms512m -Xmx3072m
因此该应用最多可以使用 3GB 的堆空间。但是你可以看到java进程(RES内存)已经使用了超过6GB的内存。
此时很明显我需要查看非堆空间。有所谓的 Metaspace,我认为它面临内存泄漏。我已经完成了以下检查:
# jcmd 18 GC.heap_info
18:
PSYoungGen total 984576K,used 647154K [0x0000000780000000,0x00000007c0000000,0x00000007c0000000)
eden space 925696K,63% used [0x0000000780000000,0x00000007a3e83970,0x00000007b8800000)
from space 58880K,99% used [0x00000007b8800000,0x00000007bc179030,0x00000007bc180000)
to space 64000K,0% used [0x00000007bc180000,0x00000007bc180000,0x00000007c0000000)
ParOldGen total 1671168K,used 1048981K [0x0000000700000000,0x0000000766000000,0x0000000780000000)
object space 1671168K,62% used [0x0000000700000000,0x0000000740065488,0x0000000766000000)
Metaspace used 2235431K,capacity 2246406K,committed 2252780K,reserved 2981888K
class space used 317765K,capacity 320038K,committed 321024K,reserved 1048576K
这里我看到使用的内存是 647154K + 1048981K 的堆和 2235431K 的元空间(非堆)。总数为 3931566K = 3840M = 3.75 GB。但是 Java 进程消耗的剩余内存是多少呢?很多:6.18 - 3.75 = 2.43 GB 内存。
# jstat -gccapacity 18
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
174592.0 1048576.0 1048576.0 64000.0 58880.0 925696.0 349696.0 2097152.0 1671168.0 1671168.0 0.0 2981888.0 2252780.0 0.0 1048576.0 321024.0 289 13
这里我使用这个公式计算整个 Java 内存:
NGCMN + S0C + S1C + EC + OGCMN + MC + CCSC = 174592 + 64000 + 58880 + 925696 + 349696 + 2252780 + 321024 = 4146668K = 3.95 GB
根据 GC.heap_info
计算出的空间略大于 3.75 GB,但仍远低于 Java 进程消耗的 6.18 GB。
- 如何确定哪种类型的 Java 内存占用了 2.43 GB?
- 如何限制内存或确保及时清除内存以避免 OutOfMemory 崩溃?
- 我应该设置像 -XX:MaxMetaspaceSize -XX:MaxMetaspaceFreeRatio 这样的额外参数吗?如果是这样,这些的合理值是多少?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)