ThreadMXBean.getThreadAllocatedBytes(long id)中包含哪些JVM运行时数据区域

问题描述 投票:1回答:1

我试图获取某些代码段的内存消耗。经过一番搜索,我意识到可以使用ThreadMXBean.getThreadAllocatedBytes(long id)实现这一目标。因此,我使用以下代码测试了此方法:

    ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
    long id = Thread.currentThread().getId();
//      new Long(0);
    long beforeMemUsage = threadMXBean.getThreadAllocatedBytes(id);
    long afterMemUsage = 0;

    {
        // put the code you want to measure here
        for (int i = 0; i < 10; i++) {
            new Long(i);
        }
    }

    afterMemUsage = threadMXBean.getThreadAllocatedBytes(id);
    System.out.println(afterMemUsage - beforeMemUsage);

我在for循环(0、1、10、20和30)中以不同的迭代时间运行此代码。结果如下:

0 Long: 48 bytes
1 Long: 456 bytes
10 Long:    672 bytes
20 Long:    912 bytes
30 Long:    1152 bytes

1与10、10与20以及20与30之间的差异很容易解释,因为Long对象的大小为24个字节。但是我对0和1之间的巨大差异感到困惑。实际上,我猜这是由类加载引起的。因此,我对第3行代码和结果如下进行了注释:

0 Long: 48 bytes
1 Long: 72 bytes
10 Long:    288 bytes
20 Long:    528 bytes
30 Long:    768 bytes

看来结果似乎证实了我的猜测。但是,在我看来,类结构的信息存储在“方法区”中,它不是堆内存的一部分。正如ThreadMXBean.getThreadAllocatedBytes(long id)的Javadoc所指示的,它返回the total amount of memory allocated in heap memory。我错过了什么吗?

经过测试的JVM版本是:

java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

谢谢!

java memory-management jvm
1个回答
1
投票

new Long(0)的首次调用导致由new字节码引用的常量池条目的解析。首次解析CONSTANT_Class_info时,JVM加载引用的类-java.lang.Long

ClassLoader.loadClass用Java实现,它当然可以分配Java对象。例如,ClassLoader.loadClass方法在getClassLoadingLock中创建一个新的锁定对象和一个新条目:

getClassLoadingLock

此外,当在系统字典中进行类名查找时,JVM会创建一个新的String对象。

我使用parallelLockMap记录了加载 protected Object getClassLoadingLock(String className) { Object lock = this; if (parallelLockMap != null) { Object newLock = new Object(); lock = parallelLockMap.putIfAbsent(className, newLock); if (lock == null) { lock = newLock; } } return lock; } 类时JVM所做的所有堆分配。分配了13个Java对象。这是可点击的交互式火焰图:

async-profiler

该图由以下测试程序生成:

java.lang.Long

如何运行:

Allocation Flame Graph

这里import one.profiler.AsyncProfiler; public class ProfileHeapAlloc { public static void main(String[] args) throws Exception { AsyncProfiler profiler = AsyncProfiler.getInstance(); // Dry run to skip allocations caused by AsyncProfiler initialization profiler.start("_ZN13SharedRuntime19dtrace_object_allocEP7oopDesci", 0); profiler.stop(); // Real profiling session profiler.start("_ZN13SharedRuntime19dtrace_object_allocEP7oopDesci", 0); new Long(0); profiler.stop(); profiler.execute("file=alloc.svg"); } } java -Djava.library.path=/path/to/async-profiler -XX:+DTraceAllocProbes ProfileHeapAlloc 函数的_ZN13SharedRuntime19dtrace_object_allocEP7oopDesci,每当mangled name标志打开时,JVM会为每个堆分配调用它。

© www.soinside.com 2019 - 2024. All rights reserved.