【问题标题】:Will ThreadMXBean#getThreadAllocatedBytes return size of allocated memory or objects?ThreadMXBean#getThreadAllocatedBytes 会返回分配的内存或对象的大小吗?
【发布时间】:2016-07-10 15:37:12
【问题描述】:

我想雇用com.sun.management.ThreadMXBean 来做这样的事情:

long before = threadMxBean.getThreadAllocatedBytes(currentThreadId);
seriousBusiness(); // some calls here
long after = threadMxBean.getThreadAllocatedBytes(currentThreadId);
long allocDiff = after - before; // use for stats or whatever

问题是,这个方法实际返回的是什么:方法调用时分配的新内存量分配对象的大小?要清楚我的意思是什么:

1) 假设我在 seriousBusiness() 调用中分配了一个巨大的数组,因此为此目的分配了一个新的内存区域,getThreadAllocatedBytes 会增加相应的值。

2) 一段时间过去了,有一个 GC 运行,未使用的数组被收集,内存区域现在​​是空闲的。

3) 我再次调用(在同一个线程中),JVM 发现它不需要分配新内存并为新目的重用该内存区域,这导致getThreadAllocatedBytes 值没有增长。

我可能对 JVM 内存管理的工作方式不太准确,但问题应该很清楚。

另外,如果第一个假设是正确的(仅计算新的内存分配),那么进行per-thread object allocations / memory footprint 测量的正确方法是什么?

UPD。我试着检查自己:http://pastebin.com/ECQpz8g4。 (代码中的sleep是为了让我用JMC连接到JVM)。

TL;DR:分配一个巨大的 int 数组,然后对它进行 GC,然后分配一些新对象并检查分配的内存。这是我得到的:

因此,看起来 GC 实际运行了,虽然内存肯定已分配并随后释放,但我得到了以下输出:

665328          // before everything started
4295684088      // 4 GiB allocated
4295684296      // did GC (for certain! (really?))
5812441672      // allocated a long string, took new memory

所以,我只是在等待具有 JVM 内存专业知识的人告诉我我是对还是错。

【问题讨论】:

    标签: java performance memory-management jvm jmx


    【解决方案1】:

    引用ThreadMXBean,它代表目标线程报告堆中分配的字节数,但暗示这相当于分配的对象的大小。不过有一个警告:

    返回值是一个近似值,因为一些 Java 虚拟 机器实现可以使用对象分配机制 导致分配对象的时间和时间之间的延迟 它的大小被记录

    因此,我假设堆空间的回收对报告的值没有影响,因为它只报告分配的绝对字节数,所以如果你分配 100 个字节,那么 80 个字节被回收,然后你分配另外 100 字节,这些事件结束时报告的(增量)值将是 200 字节,尽管 net 分配只有 120。

    【讨论】:

    • 谢谢,这是我一直在寻找的答案。我只是想了一种方法来证明它:用一个小的 Xmx(可能是几十兆字节)启动 VM,然后创建很多对象,直到堆满并且对象被回收 - 分配计数器仍然增加,所以它不是内存大小,但对象的大小。
    【解决方案2】:

    ThreadMXBean.getThreadAllocatedBytes 返回给定线程从一开始就分配的堆内存的累积量,即这是一个单调递增的计数器。它大致是已分配对象的总大小。

    编辑

    HotSpot JVM 中分配的堆内存没有“线程所有权”。一旦分配了内存,它就会在所有线程之间共享。因此,“每线程使用”并没有真正的意义。当JVM在堆中分配一个对象时,它并不知道这块内存之前是否被谁使用过。

    【讨论】:

    • 嗯,例如,TL​​AB 是特定于线程的。所以我们不应该绝对否认线程-内存区域的所有权关系。
    • @tkroman TLAB 在 HotSpot 中只是一种预分配块,它不保留所有权。而且它没有被重复使用;一旦 TLAB 已满,就会创建新的。
    • 是的,当我说“代表目标线程在堆中分配”时,我并不是说内存是为那个线程“保留”的,而是那个线程导致要分配的内存。
    • 我相信是您的编辑在线程中引入了“所有权”术语,以及您引用的“每线程使用”最初是“每线程”的事实对象分配' :) 但我明白了你的意思,它与我的问题和尼古拉斯在这个评论线程中所说的完全一致。重复使用“所有权”这个词是我的错误。
    • @Nicholas,这正是我要问的。没有暗示“保留记忆”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    • 2012-02-28
    • 1970-01-01
    • 2015-10-15
    相关资源
    最近更新 更多