我正在研究调试我的应用程序中的"OutOfMemoryError: Metaspace“错误。就在OOME之前,我在gc日志中看到了以下内容:
{Heap before GC invocations=6104 (full 39):
par new generation total 943744K, used 0K [...)
eden space 838912K, 0% used [...)
from space 104832K, 0% used [...)
to space 104832K, 0% used [...)
concurrent mark-sweep generation total 2097152K, used 624109K [...)
Metaspace used 352638K, capacity 487488K, committed 786432K, reserved 1775616K
class space used 36291K, capacity 40194K, committed 59988K, reserved 1048576K
2015-08-11T20:34:13.303+0000: 105892.129: [Full GC (Last ditch collection) 105892.129: [CMS: 624109K->623387K(2097152K), 3.4208207 secs] 624109K->623387K(3040896K), [Metaspace: 352638K->352638K(1775616K)], 3.4215100 secs] [Times: user=3.42 sys=0.00, real=3.42 secs]
Heap after GC invocations=6105 (full 40):
par new generation total 943744K, used 0K [...)
eden space 838912K, 0% used [...)
from space 104832K, 0% used [...)
to space 104832K, 0% used [...)
concurrent mark-sweep generation total 2097152K, used 623387K [...)
Metaspace used 352638K, capacity 487488K, committed 786432K, reserved 1775616K
class space used 36291K, capacity 40194K, committed 59988K, reserved 1048576K
}据我所见,Metaspace的容量甚至没有接近提交的大小(在本例中,是-XX:MaxMetaspaceSize=768m)。因此,我怀疑Metaspace的碎片会导致分配程序无法为新的类加载器找到新的块。
我知道-XX:PrintFLSStatistics,但这只涉及CMS,而不是本机内存。
因此,我的问题是:对于Hotspot的本机内存,是否有类似于PrintFLSStatistics的调试帮助?
这是在LinuxAMD64JRE (1.8.0_45-b14)中使用HotSpot(TM) 64位服务器VM (25.45-b02)。
发布于 2015-08-20 12:12:43
我刚刚研究了HotSpot中Metaspace的实现。Metaspace被分成几块,并使用自由职业者进行管理。因此,碎片化确实是造成问题的一个可能原因。
我还查看了HotSpot VM (-XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal)的标志,在发布版本中没有标记。
但是,Metaspace类中有一个dump()方法,它似乎是通过设置-XX:+TraceMetadataChunkAllocation标志来触发的。还有一个-XX:+TraceMetavirtualspaceAllocation,听起来是你感兴趣的。但是,这些都是“开发”标志,这意味着您需要VM的调试版本。
发布于 2015-08-20 18:06:28
@loonytune的答案工作得很好,但我想提供一些更详细的信息:
对于上下文,“Metaspace”是一个元类集合,每个类加载器一个。每个元空间都包含一个VirtualSpace对象列表,其中分配了不同大小的Metachunk。这些块包含MetaBlocks,它们是元数据的真正容器。
我需要一个调试JRE来运行这些标志,所以在这位导师之后,我签出了openjdk存储库(我将签出重命名为vm,因为构建脚本似乎与jdk8文件夹名有问题)。
~/vm$ bash configure --enable-debug
~/vm$ DISABLE_HOTSPOT_OS_VERSION_CHECK=ok make all并使用得到的vm/build/linux-x86_64-normal-server-fastdebug/images/j2re-image作为我的java运行时。
生成的日志行如下所示:
VirtualSpaceNode::take_from_committed()没有可用的8192字空间@0x00007F4cdb9350 128 K,94%使用[0x00007fedf5e22000,0x00007fedf5f13000,0x00007fedf5f22000,0x00007fedf6022000]
它表示当前VirtualSpace已满,无法容纳所请求的8192 word大小的另一个块。这将导致这个元应用程序切换到另一个VirtualSpace。
ChunkManager::chunk_freelist_allocate: 0x00007F4c0c39f8块0x00007F15397400大小128计数0免费块共计7680计数15 ChunkManager::chunk_freelist_allocate: 0x00007F4c0c39f8块0x00007fedf6021000大小512计数14自由块总数7168计数14
当分配了一个新的Metachunk时,就会发生这种情况,在第一种情况下,它的长度为128个字,并且耗尽了小块的列表。如您所见,下一个请求转到中等大小的块(大小为512),总共留下14个块空闲。一旦空闲总数达到0,就需要一个完整的GC来增加总的Metaspace大小。
请注意,指定-verbose将使您从上述两个标志获得更多的输出。
https://stackoverflow.com/questions/32117471
复制相似问题