HotSpot Serviceability Agent 的 iterateObjectsOfKlass() 太慢

问题描述 投票:0回答:2

我能够调用

ObjectHeap.iterateObjectsOfKlass
(在 SA 的帮助下)来获取属于某个类的所有对象。结果正是我所期望的,但性能却不是。

我花了超过 800 秒才得到结果,在此期间目标虚拟机被挂起。目标VM堆约为2GB。我知道

iterateObjectsOfKlass
会打电话给
iterateExact

我的问题是:这些方法是否迭代/遍历整个堆只是为了获取 1 个类的对象?我很失望,因为我的期望是对于单个类,结果应该在 10 秒内返回。

java performance jvm heap-memory jvm-hotspot
2个回答
6
投票

HotSpot Serviceability Agent 确实是强大的技术,但确实很慢。我已经在这个答案中解释了它是如何工作的。

JVM 无法快速找到特定类的所有实例。所以,是的,它必须扫描整个堆。此外,为了读取外部进程的内存,SA 对每个数据字使用

ptrace
系统调用。这就是为什么它这么慢。

您有多种选项可以更快地扫描堆:

  1. 创建外部进程的核心转储,然后针对核心转储运行 SA 工具。这比读取挂起进程的内存要快得多。请参阅相关问题
  2. 使用动态附加机制JVMTI代理注入到正在运行的进程中。代理可以使用
    IterateOverInstancesOfClass
    函数扫描本地 JVM 的堆。与 SA 相比,这会快得多,因为它只是从同一进程中读取,而不需要任何系统调用或其他任何东西。我相信 2GB 的堆只需要几秒钟。

0
投票

我在 JDK17 上尝试使用 coredump 进行 SA。看起来和attach pid一样慢,因为有LRU页面缓存。

"pool-1-thread-1" #25 prio=5 os_prio=0 cpu=1881.17ms elapsed=29538435.51s tid=0x00007f51dab59a00 nid=0x11a6f waiting for monitor entry  [0x00007f51d479b000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at sun.jvm.hotspot.debugger.PageCache.getData([email protected]/PageCache.java:57)
        - waiting to lock <0x0000000530000000> (a sun.jvm.hotspot.debugger.PageCache)
        at sun.jvm.hotspot.debugger.DebuggerBase.readBytes([email protected]/DebuggerBase.java:225)
        at sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal.readCInteger([email protected]/LinuxDebuggerLocal.java:565)
        at sun.jvm.hotspot.debugger.DebuggerBase.readCompKlassAddressValue([email protected]/DebuggerBase.java:477)
        at sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal.readCompKlassAddress([email protected]/LinuxDebuggerLocal.java:511)
        at sun.jvm.hotspot.debugger.linux.LinuxAddress.getCompKlassAddressAt([email protected]/LinuxAddress.java:83)
        at sun.jvm.hotspot.oops.NarrowKlassField.getValue([email protected]/NarrowKlassField.java:36)
        at sun.jvm.hotspot.oops.Oop.getKlass([email protected]/Oop.java:82)
        at sun.jvm.hotspot.oops.Oop.getObjectSize([email protected]/Oop.java:94)
        at com.kuaishou.alwayson.profiler.sa.oops.G1GenAccessor.lambda$processLiveRegion$1(G1GenAccessor.java:130)
        at com.kuaishou.alwayson.profiler.sa.oops.G1GenAccessor$$Lambda$51/0x0000000801097490.run(Unknown Source)
        at java.util.concurrent.Executors$RunnableAdapter.call([email protected]/Executors.java:539)
        at java.util.concurrent.FutureTask.run([email protected]/FutureTask.java:264)
        at java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1136)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:635)
        at java.lang.Thread.run([email protected]/Thread.java:959)
© www.soinside.com 2019 - 2024. All rights reserved.