如何找出确切的年轻/老年人在记忆中的位置?

时间:2015-06-02 15:13:48

标签: java jvm jmx java-memory-model

最近我能够使用sun.misc.Unsafe类获取对象的地址。

现在我试图以编程方式找到我的对象所在的实际生成。为此,我想知道每一代的起点和终点。 如果Java(Oracle JVM)提供了解决此问题的任何工具?我不相信,因为即使不同的GC也需要不同的内存结构(例如G1),这使得任务更加有趣:)

我想知道的只是代表内存中几代边界的几个数字,如下所示:

   young gen: start point - 8501702198   
              end point   - 9601256348

愿意听到关于黑魔法的最疯狂的想法,这些想法可以确定不同代区域的位置。

2 个答案:

答案 0 :(得分:4)

虽然HotSpot JVM有些复杂,但这是可行的。

关键的想法是使用VMStructs - 有关嵌入JVM共享库的HotSpot内部thisconstants的信息。

例如,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());

现在你知道了你的应用程序的对象的年龄和期限阈值,所以你可以假设如果年龄大于阈值,那么它就属于老一代。

警告: 它基于魔法和秘密知识的启发式。

  1. 如果有人在读取目标对象时会同步目标对象,它将无效,因为VM会将标头移动到堆栈并用指针替换标头堆栈
  2. 它不适用于XX:+UseAdaptiveSizePolicy,因此您应该明确禁用它。
  3. 某些对象可以在老一代中直接分配(例如因为它的大小)
  4. Type I error俯卧
  5. 这种方法是非法的,不安全的,可能不正确且依赖于jvm