堆、堆栈、永久空间

问题描述 投票:0回答:2
  • Java内存空间(Perm空间、栈空间、堆空间)有什么区别?
  • JVM 什么时候使用其中之一?
  • 如果我使用 Scala/Groovy/等,有什么区别吗?
java memory jvm heap-memory stack-memory
2个回答
93
投票

简单

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

例如:

Student std = new Student();

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

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

16
投票

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

概述

  • 堆栈
    • 按线程分配
    • 存储本地引用和原语
    • 这是作用域内存 - 当方法或线程结束时,堆栈中的所有数据都会丢失
    • 具有最快的访问速度,因此本地原语的使用速度比本地对象更快
    • 所有分配的对象实例都存在这里
    • 分为Generations,最年轻的一代是GC首先看的位置
    • 适用于所有线程,因此分配和释放应该同步
    • 此内存可能会变得碎片化(但您通常不会自己管理它
  • 永久代元空间
    • 存储加载的类信息
    • 存储不可变信息(基元、内部字符串)
    • 存储静态类成员

示例代码

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 空间被所谓的元空间取代。它的功能仍然相同,但可以自动调整大小 - 默认情况下,元空间会自动将其在本机内存中的大小增加到最大值(在 JVM 参数中指定),但 PermGen 始终具有与堆内存相邻的固定最大大小。

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

最后,要了解更多信息,我在 StackOverflow 上见过的关于此主题的最佳答案是这里

© www.soinside.com 2019 - 2024. All rights reserved.