java中的堆和栈

70 阅读3分钟

今天来介绍java中的堆和栈的应用


jvm运行时的数据区

jvm运行时划分了以下五个区域

image.png

JVM栈

JVM栈(stack)服务的就是不带native的方法所执行的内存空间,局部变量会保存在栈帧里面。 java栈有以下几个特性

  • 每当java程序执行一个方法,都会在线上分配一块只属于这个方法内存区域,称为的栈帧。
  • 每当java程序执行一个方法,都会将一个存储该方法信息的栈帧压入栈中,称为方法进栈
  • 方法进栈同时局部变量开辟内存空间存储值,局部变量生效
  • 当方法执行完毕之后,该方法的栈帧随之销毁,称之为出栈
  • 方法栈帧被销毁的同时,局部变量也被销毁,局部变量失效

只有处于栈顶时,对应的栈才会生效,表示正在执行的栈,称为当前栈。

栈帧里面存储的内容有这么几大类

  • 局部变量表
  • 操作栈
  • 动态连接
  • 返回地址

例如如下代码:

public class TestPlayground {
    public static void main(java.lang.String[] args){
        a1();
    }

    public static void a1(){
        System.out.println("111");
        a2();
    }    
    public static void a2(){
        System.out.println("2222");
    }
}

栈应该是这样运作的

image.png

堆(heap)是JVM内存中最大的一块,所有引用数据类型,new出来的东西(对象或者实例)都放在堆上。

所以new关键字的语义就是在堆上开辟一片空间给相应的对象。这片空间就是内存地址,这个内存地址是留给外界访问的。

定义引用数据类型时的栈和堆

在引用数据类型创建时,即在堆内存了内容,也在栈里面存了内容 比如:

int[] arr=new int[3];

可以把这段代码看成两部分,右边 new int[3] 是数组的创建,左边 int[] arr 是创建了一个引用数据类型的局部变量,所以:

new int[3]:创建在堆内

int[] arr: 创建在栈内,栈内存的是堆内存的地址

即:

image.png

栈和堆的生命周期

栈:栈帧出栈了,生命周期就结束了。

堆:堆上的对象使用完毕后,随着方法的出栈,对象的引用就会被销毁。这个时候对象就没有引用指向它,而是"孤零零"的单独存在于堆上,这种对象意味着我们就无法再次使用它了,这种对象没有意义了。在Java中,我们把这种对象称之为垃圾或者垃圾对象,它们会等待垃圾回收器进行内存回收。

垃圾回收机制(Garbage Collection简称GC)

  • 堆上的对象变成垃圾后,并不是立刻就会被回收,而是需要GC通过一系列的算法来决定它是否被回收。
  • Java的GC机制是全自动的,程序员几乎无法干涉和主动回收垃圾。这一方面为Java程序员的开发节省了大量的精力(无需花费大量精力来管理堆内存),相比于C++的全手动回收垃圾对象,Java在GC机制上的创新是Java能够如此流行的重要原因之一。但另一方面,一旦GC这种机制出现问题,对Java而言将会是非常难以解决的问题。malloc() free()
  • 垃圾回收是Java和C++之间的一道围墙,墙外的人想进来,墙内的人却想出去。