Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 异常的内存分配_Java_Memory_Garbage Collection - Fatal编程技术网

Java 异常的内存分配

Java 异常的内存分配,java,memory,garbage-collection,Java,Memory,Garbage Collection,您能解释一下,异常实例或它的子实例在内存中的分配位置吗?是堆还是栈,还是别的什么 谢谢 默认情况下,Java中的所有对象都分配在一个堆中。您可以特别指出,关于异常实例,因为它们通常被传递给调用方方法,因此它们不可能位于堆栈上。异常s(以及所有可丢弃的s)与任何其他类型的Java对象一样。因此,它们将出现在堆中。正如MusiKk指出的那样,堆栈只能保存原语值或对象引用。它们是在堆上创建的,但这有什么关系呢?因为大多数JVM的所有对象都是在堆上创建的,异常不是异常。) JVM可以使用转义分析在堆栈上

您能解释一下,异常实例或它的子实例在内存中的分配位置吗?是堆还是栈,还是别的什么


谢谢

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

异常
s(以及所有可丢弃的s)与任何其他类型的Java对象一样。因此,它们将出现在堆中。正如MusiKk指出的那样,堆栈只能保存原语值或对象引用。

它们是在堆上创建的,但这有什么关系呢?

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

JVM可以使用转义分析在堆栈上分配对象,但是这通常限于仅在一个方法中使用且未返回的对象。i、 e.例外情况极不可能是一个好的候选情况


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

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);
    }
}
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 before getStackTrace()
detailMessage: here
cause: {self}
stackTrace: null

Throwable after getStackTrace()
detailMessage: here
cause: {self}
stackTrace: Array of class java.lang.StackTraceElement

因此问题出现了,用于创建StackTraceElement的信息保留在哪里。查看代码,本机方法用于访问信息。有一个神秘的字段叫做
backtrace
,使用反射无法看到它

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);
    }
}
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对象更大。

对象总是在堆中。堆栈上只能有引用。在99.9%的情况下,是的。。。但是,最新的JDK可以使用Escape分析来确定对对象的引用是否超出了当前范围,如果没有,它根本不会创建对象,如果空间允许,它会将基本字段直接放入堆栈中。再说一次,
Throwable
的字段也是对象,因此它们无论如何都必须放在堆上,所以我想我并不是一直都在思考问题。如果JVM想要符合VM规范,它就不能在堆栈上创建对象。堆栈只能保存引用。请参阅JVM的3.6.1:@musiKk,我同意编译器不能为虚拟机分配虚拟堆栈上的对象。然而,JVM编译为本机代码时所做的工作可能非常不同。我也在考虑转义分析,但由于
Throwable
的字段也是对象,因此可能无法工作。请看我的答案。JVM而不是编译器执行转义分析。因此,虚拟机的字节码是什么并不重要。