JDK 6 update 25 里添加的一个新功能非常有趣,可以按照线程来跟踪(GC堆)内存的分配量。
JMX中,该功能由ThreadMXBean上新增的几个方法提供。详情可见下面例子。
ThreadMXBean.getThreadAllocatedBytes(long threadId)的用法基本上可以看成跟System.currentTimeMillis()用于计时的用法一样,在两点上记录并且求差即可。
import java.lang.management.ManagementFactory;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import com.sun.management.ThreadMXBean;
@SuppressWarnings("restriction")
public class TestThreadAllocateBytes {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Task()).start();
}
while(true){
}
}
public static class Task implements Runnable{
@Override
public void run() {
ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
long startSize = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId());
System.out.println(Thread.currentThread().getName() + " start " + startSize);
String msg = "hello world";
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(msg + i);
}
long endSize = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId());
long costBytes = endSize - startSize;
System.out.println(Thread.currentThread().getName() + " end " + endSize);
System.out.println(Thread.currentThread().getName() + " 消耗了内存: " + readableFileSize(costBytes));
try {
Thread.sleep(1000 * 1000 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static String readableFileSize(long size) {
if(size <= 0) return "0";
final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
}
输出
Thread-0 start 7568
Thread-0 end 1862032
Thread-1 start 48
Thread-1 end 1849304
Thread-1 消耗了内存: 1.8 MB
Thread-0 消耗了内存: 1.8 MB
通过jvisualvm 查看JVM的内存分配
1.查看每个对象占用的堆内存大小
#####2.查看每个线程占用的堆内存大小
参考资料