最近我能够使用sun.misc.Unsafe类获取对象的地址。
现在我试图以编程方式找到我的对象所在的实际生成。为此,我想知道每一代的起点和终点。 如果Java(Oracle JVM)提供了解决此问题的任何工具?我不相信,因为即使不同的GC也需要不同的内存结构(例如G1),这使得任务更加有趣:)
我想知道的只是代表内存中几代边界的几个数字,如下所示:
young gen: start point - 8501702198
end point - 9601256348
愿意听到关于黑魔法的最疯狂的想法,这些想法可以确定不同代区域的位置。
答案 0 :(得分:4)
虽然HotSpot JVM有些复杂,但这是可行的。
关键的想法是使用VMStructs
- 有关嵌入JVM共享库的HotSpot内部this和constants的信息。
例如,ParallelScavengeHeap::_young_gen
VM全局变量包含指向PSYoungGen
结构的指针,该结构具有_virtual_space
成员,具有Parallel collector年轻代的边界。同样,GenCollectedHeap::_gch
全局指向描述CMS收集器生成的结构。
我已经制作了types来演示VMStructs的用法。它是纯Java,不需要额外的库,但它非常依赖于未记录的JDK内部,并且可能不适用于所有Java版本。我已经在Windows和Linux上对JDK 8u40和JDK 7u80进行了测试。
答案 1 :(得分:2)
我不知道如何准确地了解年轻一代和老一代的边界(甚至不确定它是否可能)。在G1的情况下,它变得更加复杂,因为由于G1的不寻常的堆结构,它允许具有多个旧的一代区域。
但是你可以使用棘手的启发式来确定对象是否属于老一代,而不知道世代的边界。
让我们使用一些关于hotspot internals的 black magic 秘密知识:每个对象都包含标题,其中包含有关锁定,身份哈希码以及最重要的年龄的所有必要信息即可。
提取年龄将如下所示:
return unsafe.getByte(targetObject, 0L) & 0x78;
其中0x78是对象标题中与其年龄相对应的掩码(从第4位到第7位)。
通过Management API获取MaxTenuringThreshold
参数:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
server,
"com.sun.management:type=HotSpotDiagnostic",
HotSpotDiagnosticMXBean.class);
int threshold = Integer.valueOf(bean.getVMOption("MaxTenuringThreshold").getValue());
现在你知道了你的应用程序的对象的年龄和期限阈值,所以你可以假设如果年龄大于阈值,那么它就属于老一代。
警告:强> 它基于魔法和秘密知识的启发式。
XX:+UseAdaptiveSizePolicy
,因此您应该明确禁用它。