异常的内存分配

时间:2011-05-06 08:54:24

标签: java memory garbage-collection

请您解释一下,Exception或其子项的实例在内存中分配的位置?它是堆还是堆栈,还是其他东西?

谢谢!

4 个答案:

答案 0 :(得分:3)

对于大多数JVM,所有Object都在堆上创建,而Exception也不例外。 ;)

JVM可以使用Escape Analysis在堆栈上分配对象,但是这通常仅限于仅在一个方法中使用而不返回的对象。即,例外情况极不可能是一个好的候选人。


在许多JVM上创建Throwables(包括Exception)的方式特别之处在于,在需要之前不会创建堆栈跟踪元素。这是因为大多数时候不需要它们而且创建起来很昂贵。但是,创建堆栈跟踪的信息保留在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 296

Throwable的大小远远大于它所拥有的字段。可以假设一些附加信息存储在堆上以帮助这个类,但是,所有信息都存储在Throwable对象中,你希望第二种类型的Throwable更大。

答案 1 :(得分:0)

默认情况下,Java中的所有对象都在堆中分配。你可以特别说一下Exception实例,因为它们通常被传递给调用者方法,因此它们无法存在于堆栈中。

答案 2 :(得分:0)

Exception s(和所有Throwable s)就像任何其他类型的Java对象一样。因此,它们将出现在堆中。正如MusiKk指出的那样,堆栈只能保存原始值或对象引用。

答案 3 :(得分:0)

它们是在堆上创建的,但为什么这很重要?