你能解释一下,Exception的实例或它的子实例是在内存中分配的吗?是堆还是栈,还是别的什么?
谢谢!
发布于 2011-05-06 17:05:39
对于大多数JVM,所有对象都是在堆上创建的,异常不是异常。;)
JVM可以使用Escape Analysis在堆栈上分配对象,但是这通常仅限于只在一个方法中使用且不返回的对象。也就是说,异常极不可能是一个好的候选者。
在许多JVM上创建Throwable(包括异常)的方式的特殊之处在于,只有在需要时才创建堆栈跟踪元素。这是因为大多数时候不需要它们,而且创建它们的成本很高。但是,用于创建堆栈跟踪的信息由JVM保留在某个位置,并与Throwable关联,但它对调试器或反射是不可见的。
public static void main(String... args) {
Throwable t = new Throwable("here");
System.out.println("Throwable before getStackTrace()");
shallowDump(t);
System.out.println("\nThrowable after getStackTrace()");
t.getStackTrace();
shallowDump(t);
}
private static void shallowDump(Object pojo) {
for (Field f : pojo.getClass().getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())) continue;
f.setAccessible(true);
Object o;
try {
o = f.get(pojo);
if (o == pojo)
o = "{self}";
if (o instanceof Object[])
o = "Array of "+(o.getClass().getComponentType());
} catch (Exception e) {
o = e;
}
System.out.println(f.getName() + ": " + o);
}
}打印
Throwable before getStackTrace()
detailMessage: here
cause: {self}
stackTrace: null
Throwable after getStackTrace()
detailMessage: here
cause: {self}
stackTrace: Array of class java.lang.StackTraceElement因此,问题出现了,用于创建StackTraceElement的信息保留在哪里。从代码中可以看出,本机方法用于访问信息。有一个名为backtrace的神秘字段,使用反射是看不到的。
System.gc();
for (int i = 0; i < 5; i++) {
Throwable[] ts = new Throwable[10000];
long free = Runtime.getRuntime().freeMemory();
for (int j = 0; j < ts.length; j++)
ts[j] = new Throwable();
long used = free - Runtime.getRuntime().freeMemory();
System.out.printf("Average Throwable size was %,d%n", used / ts.length);
}
System.gc();
for (int i = 0; i < 5; i++) {
Throwable[] ts = new Throwable[10000];
long free = Runtime.getRuntime().freeMemory();
for (int j = 0; j < ts.length; j++)
ts[j] = Throwable.class.newInstance();
long used = free - Runtime.getRuntime().freeMemory();
System.out.printf("Average Throwable.class.newInstance() size was %,d%n", used / ts.length);
}这将获得在当前方法中创建的Throwable和通过反射在更深的方法中创建的Throwable的大小(具有更深的堆栈)
Average Throwable size was 302
Average Throwable size was 302
Average Throwable size was 302
Average Throwable size was 302
Average Throwable size was 302
Average Throwable.class.newInstance() size was 247
Average Throwable.class.newInstance() size was 296
Average Throwable.class.newInstance() size was 296
Average Throwable.class.newInstance() size was 296
Average Throwable.class.newInstance() size was 296Throwable的大小比您从它拥有的字段中预期的要大得多。我们可以假设堆上存储了一些额外的信息来帮助这个类,然而,如果所有的信息都存储在Throwable对象中,那么第二种类型的Throwable会更大。
发布于 2011-05-06 16:58:15
默认情况下,Java中的所有对象都分配在一个堆中。你可以特别提到异常实例,因为它们通常被传递给调用者方法,因此它们不可能在堆栈上。
发布于 2011-05-06 16:58:22
Java (以及所有的Throwable)就像任何其他类型的Exception对象一样。因此,它们将出现在堆中。正如MusiKk指出的,堆栈只能保存原始值或对象引用。
https://stackoverflow.com/questions/5909032
复制相似问题