【问题标题】:How to find out where exact young/old gen is located in memory?如何找出确切的年轻/老一代在内存中的位置?
【发布时间】:2015-06-02 15:13:48
【问题描述】:

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

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

这里我想知道的只是代表记忆中世代边界的几个数字,像这样:

   young gen: start point - 8501702198   
              end point   - 9601256348

很想听听你关于黑魔法的最疯狂的想法,它可以确定不同世代区域在内存中的位置。

【问题讨论】:

  • 即使您能够获得该信息,它在您获得它的那一刻也将是陈旧的,因为 GC 可以在此期间运行并移动生成边界(G1 重新指定区域,其他 GC 可以移动年轻/旧边界)。同样,由于对象被移动,您所做的任何指针运算都会过时。
  • 我建议你看看github.com/serkan-ozal/jillegal 这可能是使用 unsafe 挖掘 JVM 内部的最佳库。您可以获取对象存活下来的 GC 计数,而不是查看地址。这可能会告诉你它在哪个地区。

标签: java jvm jmx java-memory-model


【解决方案1】:

这在 HotSpot JVM 中是可能的,尽管有点复杂。

关键思想是使用VMStructs——将HotSpot内部constantstypes的信息嵌入到JVM共享库中。

例如,ParallelScavengeHeap::_young_gen VM 全局变量包含指向PSYoungGen 结构的指针,该结构具有_virtual_space 成员和并行收集器的年轻代的边界。同样,GenCollectedHeap::_gch global 指向描述 CMS 收集器生成的结构。

我制作了一个proof-of-concept project 来演示VMStructs 的用法。它是纯 Java,不需要额外的库,但它深深依赖于未记录的 JDK 内部结构,并且可能不适用于所有 Java 版本。我已经在 Windows 和 Linux 上的 JDK 8u40 和 JDK 7u80 上对此进行了测试。

【讨论】:

  • 这样可以获取 Universe:: 常量吗?
  • @qwwdfsad 是的,列出的所有内容here
  • 谢谢!这就是我一直在寻找的
【解决方案2】:

我不知道如何准确地确定年轻一代和老一代的边界(甚至不确定是否可能)。在 G1 的情况下,它变得更加复杂,因为由于 G1 不寻常的堆结构,它允许拥有多个老年代区域。

但是您可以使用棘手的启发式方法来确定对象是否在老年代而不知道代际边界。

让我们使用一些关于hotspot internalsblack 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 2020-05-16
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    相关资源
    最近更新 更多