我需要以编程方式找出给定的Java对象占用的内存量,包括它所引用的对象占用的内存。以编程方式计算Java对象占用的内存,包括它引用的对象
我可以生成内存堆转储并使用工具分析结果。但是,生成堆转储需要相当长的时间,并且需要使用此工具来读取转储以生成报告。考虑到我可能需要多次这样做,如果我可以在我的项目中添加一些代码,使得我的值为“运行时”,我的工作就会更加敏捷。
我怎么能最好地实现这一目标?
PS:我特别有型javax.xml.transform.Templates
我需要以编程方式找出给定的Java对象占用的内存量,包括它所引用的对象占用的内存。以编程方式计算Java对象占用的内存,包括它引用的对象
我可以生成内存堆转储并使用工具分析结果。但是,生成堆转储需要相当长的时间,并且需要使用此工具来读取转储以生成报告。考虑到我可能需要多次这样做,如果我可以在我的项目中添加一些代码,使得我的值为“运行时”,我的工作就会更加敏捷。
我怎么能最好地实现这一目标?
PS:我特别有型javax.xml.transform.Templates
的对象的集合,您将需要使用反射了点。得到的一段代码过于复杂,我在这里发表(尽管它很快将作为GPL工具我建立的一部分),但其主要思想是:
您需要分别对待数组(8个头的tes,4字节的长度字段,4 *长度字节的表,加上任何内部使用的对象)。您需要使用反射来处理其他类型的对象迭代通过字段(以及它的父字段)。
您还需要在递归期间保留一组“已见”对象,以免在多处引用多次对象。
一个很好的通用解决方案是使用堆大小增量。这涉及最少的工作,并且可以在任何类型的对象/对象图之间重用。通过实例化和销毁对象多次并在其间收集垃圾,然后取平均值,避免编译器和JVM优化,这些优化会改变结果并获得相当准确的结果。如果你需要一个精确的答案到这个字节,那么这可能不是你的解决方案,但是对于我所知道的所有实际应用(分析,内存需求计算)来说,它工作得非常好。下面的代码将做到这一点。
public class Sizeof {
public static void main(String[] args)
throws Exception {
// "warm up" all classes/methods that we are going to use:
runGC();
usedMemory();
// array to keep strong references to allocated objects:
final int count = 10000; // 10000 or so is enough for small ojects
Object[] objects = new Object[count];
long heap1 = 0;
// allocate count+1 objects, discard the first one:
for (int i = -1; i < count; ++i) {
Object object;
//// INSTANTIATE YOUR DATA HERE AND ASSIGN IT TO 'object':
object=YOUR OBJECT;
////end your code here
if (i >= 0) {
objects[i] = object;
}
else {
object = null; // discard the "warmup" object
runGC();
heap1 = usedMemory(); // take a "before" heap snapshot
}
}
runGC();
long heap2 = usedMemory(); // take an "after" heap snapshot:
final int size = Math.round(((float)(heap2 - heap1))/count);
System.out.println("'before' heap: " + heap1 +
", 'after' heap: " + heap2);
System.out.println("heap delta: " + (heap2 - heap1) +
", {" + objects[0].getClass() + "} size = " + size + " bytes");
}
// a helper method for creating Strings of desired length
// and avoiding getting tricked by String interning:
public static String createString(final int length) {
final char[] result = new char[length];
for (int i = 0; i < length; ++i) {
result[i] = (char)i;
}
return new String(result);
}
// this is our way of requesting garbage collection to be run:
// [how aggressive it is depends on the JVM to a large degree, but
// it is almost always better than a single Runtime.gc() call]
private static void runGC()
throws Exception {
// for whatever reason it helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r) {
_runGC();
}
}
private static void _runGC()
throws Exception {
long usedMem1 = usedMemory(), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 1000); ++i) {
s_runtime.runFinalization();
s_runtime.gc();
Thread.currentThread().yield();
usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
}
private static long usedMemory() {
return s_runtime.totalMemory() - s_runtime.freeMemory();
}
private static final Runtime s_runtime = Runtime.getRuntime();
} // end of class
看起来好像已经有一个工具可以做到这一点,称为Classmexer。
我自己并没有尝试过,但是在我翻身之前我会走那条路。
我wouldnt称这是一个确切的愚蠢。 – Inisheer 2009-04-16 18:10:41
嗯,不完全是一个骗局,因为原来的问题未能提供一个在这方面可用的答案... – Varkhan 2009-04-16 18:11:03
它提供了几个。 – erickson 2009-04-16 18:46:34