【问题标题】:Heap vs Stack vs Perm Space堆 vs 堆栈 vs 永久空间
【发布时间】:2011-10-11 17:09:15
【问题描述】:
  • Java 内存空间(Perm Space、Space Stack、Heap Space)之间有什么区别?
  • JVM 什么时候使用一个或另一个?
  • 如果我使用 Scala/Groovy/等,有区别吗?

【问题讨论】:

标签: java memory jvm heap-memory stack-memory


【解决方案1】:

请原谅我为这样一个老问题添加答案 - 当前答案很好,但由于静态代码和 Java 8 更新而错过了一些边缘情况。

概述

  • 堆栈
    • 按线程分配
    • 存储本地引用和原语
    • 这是作用域内存 - 当方法或线程结束时,堆栈中的所有数据都会丢失
    • 具有最快的访问速度,因此使用本地原语比使用本地对象更快
    • 所有分配的对象实例都存在这里
    • 分代,最年轻的代是 GC 查找的第一个位置
    • 适用于所有线程,因此分配和释放应该同步
    • 此内存可能会变得支离破碎(但您通常不会自己管理它
  • PermGen
    • 存储加载的类信息
    • 存储不可变信息(Primatives、interned Strings)
    • 存储静态类members

示例代码

public class SimpleVal { //The Class (loaded by a classloader) is in the PermGen

    private static final int MAGIC_CONSTANT = 42; //Static fields are stored in PermGen
    private static final SimpleVal INSTANCE = new SimpleVal(1); //Static field objects are created in the heap normally, with the reference in the PermGen ('class statics' moved to the heap from Java 7+)
    private static SimpleVal previousInstance; //Mutable static fields also have their reference in PermGen so they can easily cause memory leaks

    private int value; //Member variables will be part of the heap

    public SimpleVal(int realValue) {
        value = realValue;
        ...
    }

    public static int subtract(SimpleVal val1, SimpleVal val2) {
         ....
    }

    public int add(SimpleVal other) { //Only one copy of any method (static or not) exists - in PermGen
         int sum = value + other.value; //Local values in methods are placed in the Stack memory
         return sum;
    }

}

public static void main(String[] args) {

    SimpleVal val1 = null;
    SimpleVal val2 = new SimpleVal(3); //Both of these variables (references) are stored in the Stack 

    val1 = new SimpleVal(14); //The actual objects we create and add to the variables are placed in the Heap (app global memory, initially in the Young Gen space and later moved to old generation, unless they are very large they can immediately go old gen)

    int prim = val1.add(val2); //primitive value is stored directly in the Stack memory
    Integer boxed = new Integer(prim); //but the boxed object will be in the heap (with a reference (variable) in the Stack)

    String message = "The output is: "; //In Java 7+ the string is created in the heap, in 6 and below it is created in the PermGen
    System.out.println(message + prim);

}

Java 8 注意: PermGen 空间已替换为所谓的元空间。这仍然具有相同的功能,但可以自动调整大小 - 默认情况下,Metaspace 自动将其在本机内存中的大小增加到最大值(在 JVM 参数中指定),但 PermGen 始终具有与堆内存连续的固定最大大小。

Android 注意:从 Android 4.0(实际上是从 3.0)Android 应该遵守所描述的内存合同 - 但在旧版本上是 implementation was broken。 Android-Davlik 中的“堆栈”内存实际上是基于寄存器的(指令大小和计数在两者之间有所不同,但对于开发人员来说,功能保持不变)。

最后,有关更多信息,我在 StackOverflow 上看到的关于此主题的最佳答案是 here

【讨论】:

    【解决方案2】:

    简单

    • 堆空间:所有活动对象都分配在这里。
    • 堆栈空间:存储对方法调用或变量实例化中变量的对象的引用。
    • Perm 空间:存储加载的类信息

    例如:

    Student std = new Student();
    

    执行上面一行后内存状态会是这样的。

    • 堆:存储“new Student()”
    • 堆栈:存储有关“std”的信息
    • Perm Space:存储有关学生班级的信息

    【讨论】:

    • 堆栈还存储原始文字。
    • @Daniel:感谢您提供的信息。我不知道,我会更多地研究它。
    • @Daniel,很抱歉吹毛求疵,但 java.util.Stack 中的 Satastructure 堆栈与 JVM 中的“堆栈”或堆栈在真实计算机中的工作方式完全无关,除了它是一个后进先出结构。所以再次:在 JVM 的堆栈上没有存储任何内容。堆栈用于将参数传递给被调用的方法,仅此而已。也许看看字节码是如何工作的以及如何指定 JVM 或查看一个真正的处理器的真正汇编器可能有助于理解这一点。 Kowser:thanx for the link ;D 我知道 GC 是如何工作的,我年轻的时候自己做了一些。不错的链接,不过
    • @Angel 我不是在谈论 java.util.Stack,我是在谈论 stack。如果东西没有存储在堆栈中,你怎么能从堆栈中检索它?如果您要谈论汇编程序而不是堆栈概念,则 i386 上的push 操作码 store 数据在堆栈中——它调整一个寄存器,然后将数据写入内存中指向的位置它。在某些汇编语言(例如 6502 的)store 中调用了这种写入内存的行为。我开始认为你对“商店”这个词有一些特殊的定义。
    • @Angel 回到JVM,你认为当它执行操作码iconst_1时会发生什么?
    猜你喜欢
    • 2011-06-18
    • 2021-03-15
    • 2015-06-17
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 2017-11-06
    相关资源
    最近更新 更多