在java中,内存分为两种,一种是栈(PC、Stack、Native Stack)内存,另一种是堆(堆、方法区)内存。
栈内存
用来存放在方法中定义的一些基本数据类型的变量和引用类型的变量。当在一段代码块中定义一个变量时,JVM就在栈中为这个变量分配内存空间,当超过变量的作用域后,JVM会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
堆内存
用来存放运行时创建的对象。可以在栈中定义一个特殊的变量,这个变量的取值等于对象在堆内存中的首地址,在栈中的这个特殊的变量就是堆中对象的引用变量,以后可以在程序中使用栈中的引用变量访问堆中的对象。对象在没有引用变量指向它的时候,才变成垃圾,不能被使用,但仍然占着内存,在随后一个不确定的时间被垃圾收集器回收掉。这个也是java比较占内存的主要原因。
区别
1.存放内容不同
栈内存:用来存放在方法中定义的一些基本数据类型的变量和引用类型的变量。
堆内存:用来存放运行时创建的对象。
2.生命周期不同
栈的生命周期与线程相同,随线程而生,随线程而亡,是线程私有的。
堆的生命周期与JVM相同,JVM启动时创建,JVM停止时销毁,是线程共享的。
3.内存回收管理不同
栈随线程而生,随线程而亡。每个方法被执行的时候都会创建一个栈帧,栈帧随着方法的进入和退出做入栈和出栈操作, 实现了自动内存清理。
堆是线程共享的内存区域,没有确定的销毁时间。因此,内存回收主要集中于堆中,在堆中分配的内存由垃圾收集器来管理回收。
4.存取速度不同
栈的存取速度较快,仅次于寄存器。但栈的数据大小与生存期必须是确定的,缺乏灵活性。
堆在运行时动态分配内存,生存期不用提前告诉编译器,这也导致了堆的存取速度较慢。
备注:
堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。
这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!