java - Java中,哪些对象放在栈上,哪些放在堆上?

标签 java heap-memory stack-memory

对于 Java 函数中的语句:

Xxx xxx = new Xxx() {
    public Abc abc(final Writer out) {
        return new SomeFunction(out) {
            boolean isDone = false;
            public void start(final String name) {
                /* blah blah blah */
            }
        };
    }
};

哪些变量(包括函数)放在堆上,哪些将放在堆栈上?

我问这个问题的原因是 JVM 中的段错误:

kernel: java[14209]: segfault at 00002aab04685ff8 rip 00002aaab308e4d0 rsp 00002aab04685ff0 error 6

00002aab04685ff800002aab04685ff0 很近,看来栈增长太快了。我尝试调查这部分代码,怀疑是否是多次调用该函数时出现问题的原因。有没有可能是堆上的一些变量引用了栈没有清空?

最佳答案

关于特定对象是否进入堆的问题有点牵扯。

一般来说,在Java中,所有的对象都分配在堆上,因为一个方法可能会返回或存储一个指向对象的指针。如果该对象已被放入堆栈,则下次将堆栈帧放在那里时它会被覆盖。

但是,HotSpot JIT 编译器会做一些叫做 Escape Analysis 的事情.该分析通过查看方法的代码来查明对象是否“脱离”了方法的范围。如果一个对象没有转义,编译器可以安全地将它分配到堆栈上。

维基百科有一些关于 Escape Analysis in Java 的更多信息,也关于多线程和锁定。


关于堆栈溢出:调用堆栈上的堆栈帧总是在方法完成后被删除。实际上,甚至不需要明确删除它。下一帧将覆盖之前的内容。

此外,尽管在其他语言(如 C)中,将非常大的对象放入堆栈可能会导致堆栈溢出,但我认为这不会在 Java 中发生。我希望 Sun(Oracle)的工程师足够聪明,不会让 VM 在堆栈上存储巨大的对象。

所以出现栈溢出的唯一可能是嵌套方法调用过多。由于堆栈空间足够大,可以处理任何“正常”方法调用嵌套,因此堆栈溢出通常表示代码中存在无限(或非常大的)递归。

关于java - Java中,哪些对象放在栈上,哪些放在堆上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10481528/

相关文章:

java - 在jdbc元数据中获取columnCount = 1

c++ - 如果我在 C++ 中的一个线程中分配内存,我可以在另一个线程中取消分配它吗

node.js - Heroku 服务器在部署 "JavaScript heap out of memory"应用程序时崩溃并显示 'react-admin'

c++ - malloc 和 new 是否相互了解?

C变量分配时间和空间

java - Docker 上的 Spring Boot Admin 在 Docker 上看不到其他应用程序

java - 格式日期Java

c++ - 在函数中创建的对象,它是保存在堆栈中还是堆中?

c - 堆栈段中意外的内存分配

java - 使用 Dagger 将依赖项注入(inject)单例?