小白看完也能理解java中的堆和栈的概念和区别

2021/4/8 1:08:35

本文主要是介绍小白看完也能理解java中的堆和栈的概念和区别,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

任何软件在运行时,都需要在内存中开辟空间。Java程序也不例外,也需要在运行时开辟空间,而Java程序运行时基于Java虚拟机(Java Virtual Machine,下文简称JVM)上运行,并对其做了细致的划分,栈和堆就是JVM划分出来的内存区域。

JVM内存的划分有五个区域:

1、寄存器

2、本地方法区(native method)

3、方法区

4、栈

5、堆

 

我们重点说下栈和堆:

栈内存中存储的都是局部变量(定义在方法内的变量、循环结构(for、while、do...while)内定义的也是局部变量),要加载局部变量,必须先加载方法(函数),所以方法会先进栈,然后再加载局部变量,局部变量的生命周期仅在方法执行期间,方法执行完就离开了其作用域,内存就会被释放了(实际上不是立即释放的,由GC自己判断处理的)。因为局部变量的声明周期很短(仅存在于方法内),所以栈内存的更新速度很快。

 

堆内存:存储引用类型(除了八大基本类型byte、short、int、long、char、float、double、char以外的都是引用类型。注意数组和String也是引用类型!!)的属性等对象的信息。每个new出来的对象都有其在内存中唯一的内存地址,所以也会用到栈内存也会存储对象的内存地址。

 

下面画个图更好的解释说明下。

比如在main函数里定义一个数组,

int[] arr = new int[3];

那么这句代码在内存中里发生了什么呢?

 

主函数先进栈,在栈中定义一个变量arr,接下来为arr赋值,但是右边不是一个具体的值,而是一个对象。对象创建在堆里,在堆中通过new关键字开辟空间,内存在存储数据的时候都是通过地址来体现的,地址是一块连续的二进制,然后给这个实体分配一个内存地址。数组都有索引(下标),数组这个实体在堆内存产生之后每一个空间都回进行默认的初始化(堆内存的特点,未初始化的数据是不能用的,但是在堆里是可以用的,因为在堆里的数据会隐式初始化(根据数据类型赋对应的默认值),但是栈不会,因此局部变量要使用就必须手动赋值)。

那么,堆和栈又是怎么联系起来的呢?

我们刚刚说过了,初始化对象时会给这个对象分配一个唯一的内存地址,那么JVM就会把这个内存地址给了在栈中的arr,arr就通过这个地址指向了数组。所以arr想操作数组时,就要通过这个地址,而不是直接把整个实体都赋值给他。这种我们就不再叫他基本数据类型了,而是叫引用类型。称为arr引用了堆内存中的实体。(相当于c/c++中的指针,但是Java中是没有指针这个概念的。)

如果

int[] arr = null;

这句代码就是使得arr不做任何指向,null的作用就是取消引用数据类型的指向。

当一个实体没有任何引用数据类型执行时,它在堆内种不会被立即释放,而是被当做一个垃圾,在不定时被Java的自动回收机制处理掉(GC),而在(C/C++中需要程序员手动回收,如果不回收就会在内存中越堆越多,直到内存溢出OOM,所以某种意义上来说,Java的内存管理对程序员来说更友好)。

 

总结:

1、栈内存存储局部变量(在方法内的变量)中的基本数据类型和引用类型的地址值;堆中存储对象(new出来的)具体信息

2、栈内存的更新速度要快于堆内存,因为局部变量的生命周期都很短,只在方法作用域内生效,出了作用域就无效了。

3、栈内存存放的变量生命周期一旦结束就会被释放,而堆内存中存放的对象不定时回收,这取决于JVM的自动回收机制(GC)。

 

 

参考文章:https://blog.csdn.net/pt666/article/details/70876410/



这篇关于小白看完也能理解java中的堆和栈的概念和区别的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程