【发布时间】:2013-11-18 21:39:14
【问题描述】:
如果我通过ByteBuffer.allocateDirect() 创建缓冲区,则内存存在于 Java 堆之外。有没有一种方法可以跨平台测量我的应用程序的这种内存使用情况,类似于使用Runtime.totalMemory() 和Runtime.freeMemory() 测量Java 堆使用情况?
【问题讨论】:
如果我通过ByteBuffer.allocateDirect() 创建缓冲区,则内存存在于 Java 堆之外。有没有一种方法可以跨平台测量我的应用程序的这种内存使用情况,类似于使用Runtime.totalMemory() 和Runtime.freeMemory() 测量Java 堆使用情况?
【问题讨论】:
您可以使用 MXBeans 来获取直接字节缓冲区和映射字节缓冲区使用的内存:
List<BufferPoolMXBean> pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
for (BufferPoolMXBean pool : pools) {
System.out.println(pool.getName());
System.out.println(pool.getCount());
System.out.println("memory used " + toMB(pool.getMemoryUsed()));
System.out.println("total capacity" + toMB(pool.getTotalCapacity()));
System.out.println();
}
打印类似:
direct
122
memory used 456.1562509536743 MB
total capacity456.15625 MB
mapped
0
memory used 0.0 MB
total capacity0.0 MB
toMB 函数在哪里:
private static String toMB(long init) {
return (Long.valueOf(init).doubleValue() / (1024 * 1024)) + " MB";
}
但是,我不能 100% 确定直接字节缓冲区是否是唯一可以存在于直接内存中的东西。或许还有别的……
【讨论】:
您可以在 OpenJDK/HotSpot Java 7 上使用反射来获取 Bits.reservedMemory。没有独立于平台的方式,这仅向您显示通过 ByteBuffer.allocateDirect() 的使用情况,而不是任何其他分配本机内存的方式。
另一种方法是解析/proc/{pid}/maps 并排除文件映射。这是您的进程正在使用的虚拟内存的近似值。
【讨论】:
sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getMemoryUsed() 和sun.misc.VM.maxDirectMemory() 获得价值。比反射好还是坏?
SharedSecrets 是通过低级Unsafe.allocateMemory() 分配的,则不会显示已用内存,在这种情况下,您应该自己跟踪/计算分配的内存或解析@ 987654327@ 如答案。
/proc/self/smaps,其中甚至包括多少内存是私有的以及内存中与磁盘上的内存。