首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异常的内存分配

异常的内存分配
EN

Stack Overflow用户
提问于 2011-05-06 16:54:24
回答 4查看 794关注 0票数 6

你能解释一下,Exception的实例或它的子实例是在内存中分配的吗?是堆还是栈,还是别的什么?

谢谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-05-06 17:05:39

对于大多数JVM,所有对象都是在堆上创建的,异常不是异常。;)

JVM可以使用Escape Analysis在堆栈上分配对象,但是这通常仅限于只在一个方法中使用且不返回的对象。也就是说,异常极不可能是一个好的候选者。

在许多JVM上创建Throwable(包括异常)的方式的特殊之处在于,只有在需要时才创建堆栈跟踪元素。这是因为大多数时候不需要它们,而且创建它们的成本很高。但是,用于创建堆栈跟踪的信息由JVM保留在某个位置,并与Throwable关联,但它对调试器或反射是不可见的。

代码语言:javascript
复制
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);
    }
}

打印

代码语言:javascript
复制
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的神秘字段,使用反射是看不到的。

代码语言:javascript
复制
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的大小(具有更深的堆栈)

代码语言:javascript
复制
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会更大。

票数 3
EN

Stack Overflow用户

发布于 2011-05-06 16:58:15

默认情况下,Java中的所有对象都分配在一个堆中。你可以特别提到异常实例,因为它们通常被传递给调用者方法,因此它们不可能在堆栈上。

票数 0
EN

Stack Overflow用户

发布于 2011-05-06 16:58:22

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5909032

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档