Java 堆栈和堆

什么是堆栈内存?

Java 中的堆栈是内存的一部分,包含方法、局部变量和引用变量。堆栈存储器始终以**后进先出(LIFO)**顺序引用。局部变量是在堆栈中创建的。

什么是堆内存?

堆是包含对象的内存部分,也可能包含引用变量。实例变量在堆中创建的。

Java 中的内存分配

JVM 将内存划分为以下部分。

  1. 堆栈
  2. 代码
  3. 静态

这种内存划分是其有效管理所必需的。

  • 代码部分包含字节码
  • 内存的堆栈部分包含方法、局部变量和引用变量。
  • 部分包含对象(也可能包含引用变量)。
  • 静态部分包含静态数据/方法

本地和实例变量之间的差异

实例变量在类中声明而不是在方法内声明的。

class Student{ 
int num; //num is  instance variable 
public void showData{}

局部变量在方法中声明,包括方法参数。

public void sum(int a){
int x = int a +  3;
//a , x are local variables;
}

堆栈和堆之间的区别

让我们举个例子来更好地理解这一点。

想一下你的 main 方法调用方法 m1

public void m1{
int x=20
}

在 Java 堆栈中,将从方法 m1 创建一个帧。m1 中的变量 X 也将在堆栈 m1 的帧中创建。

方法 m1 调用方法 m2。在堆栈中,在 m1 帧的顶部为 m2 创建一个新帧。

变量 bc 也将在堆栈中的帧 m2 中创建。

public void m2(int b){
boolean c;
}

同样的,方法 m2 来调用方法 m3。再次在堆栈顶部创建一个帧 m3

现在假设我们的方法 m3 正在为类 Account 创建一个对象,它有两个实例变量 int pint q

Account {
             Int p;
             Int q;
}

这是方法 m3 的代码

public void m3(){
    Account ref = new Account();
    //more code
}

语句 new Account() 将在堆中创建一个 Account 对象。

引用变量 ref 将在堆栈中创建。赋值 = 运算符将使引用变量指向堆中的对象。

一旦方法完成执行。控制流程将返回调用方法。在这里指的是方法 m2

方法 m3 的堆栈将被清除。

由于引用变量将不再指向堆中的对象,因此它可以进行垃圾回收。

方法 m2 完成执行后。它将从堆栈弹出,其所有变量将被刷新,不再可用。同样这适用于方法 m1

最终,控制流程将返回程序的起始点。通常,这是 main 方法。

如果 Object 有一个引用作为其实例变量怎么办?比如下面,

public static void main(String args[]) {
    A parent = new A(); 
    //more code } 
    class A{ 
        B child = new B(); 
        int e; //more code 
    } 
    class B{ 
        int c; 
        int d;  
        //more code 
    }
}

在这种情况下,引用变量 child 将在堆中创建,而堆又将指向其对象,如下图所示。

![Java Stack and Heap](/img/JavaJava Stack and Heap.jpg)

概要:

  • 调用方法时,会在堆栈顶部创建一个帧。
  • 一旦方法完成执行,控制流将返回到调用方法,并刷新其相应的堆栈帧。
  • 在堆栈中创建局部变量。
  • 实例变量在堆中创建并且是它们所属对象的一部分。
  • 在堆栈中创建引用变量。