为什么getThreadAllocatedBytes不一致?

3

我有一个来自JavaSpecialists newsletter的方法threadAllocatedBytes(),它调用了ManagementFactory类。

import java.lang.management.ManagementFactory;
import java.util.Arrays;

import javax.management.ObjectName;

public class MemoryTest {

    public static void main(String[] args) {
        for (int i = 0; i < 10; ++i)
            testMemory(i);
    }

    private static void testMemory(int nChars) {
        long bytes = threadAllocatedBytes();
        char[] test = new char[nChars];
        long bytes2 = threadAllocatedBytes();
        System.out.println("diff[" + +(nChars + 1) + "] = " + (bytes2 - bytes));
    }

    public static long threadAllocatedBytes() {
        try {
            return (Long) ManagementFactory.getPlatformMBeanServer().invoke(
                    new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME), "getThreadAllocatedBytes",
                    new Object[] { Thread.currentThread().getId() }, new String[] { long.class.getName() });
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }

这个程序的输出是:
diff[1] = 1072
diff[2] = 1080
diff[3] = 1080
diff[4] = 1080
diff[5] = 1080
diff[6] = 1088
diff[7] = 1088
diff[8] = 28584
diff[9] = 1088
diff[10] = 1096

为什么第8次运行显示分配更高?我该怎么做才能使它更加一致?


有趣的是,如果使用不同大小的'char[] test'运行测试,例如'new char[nChars10]'、'...'和'new char[nChars1000]',我会发现第8个分配跳跃了大约26-28 kb,与已分配内存无关。 - wero
2个回答

1

来自文档

long getThreadAllocatedBytes(long id)

返回指定ID线程在堆内存中分配的总内存大小的近似值,以字节为单位。


我并不是在抱怨它的准确性不够好,而是试图理解它在第八次运行时的异常行为。我们该如何处理它呢? - anjanb
我并没有认为你在抱怨准确性。我只是向你展示了Sun/Oracle手册中说不用担心的部分。为了进一步理解正在发生的事情,您需要深入了解虚拟机,例如垃圾收集器以及它在您使用的虚拟机中的实现方式。不要忘记gc是懒惰的,因此尽管您的线程可能已经释放了一个对象,但gc并没有必要清理它。 - Tuxxy_Thang

1
这很可能是由于使用了TLABs。为了提高性能,分配是在线程本地分配缓冲区中完成的。这使得分配非常快速,只需在保留内存的过程中简单地挤压线程本地指针,直到TLAB满为止。
为了保持性能良好,在对象适合TLAB时不进行任何分配跟踪,而是将内存作为TLAB被退役的一部分递增。
if (retire) {
  myThread()->incr_allocated_bytes(used_bytes());
}

很可能你在第8次迭代中使用了一个TLAB,因此看到了一个大的增长。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接