堆与栈
关于堆和栈的问题,对于熟悉C++的同学来说可能理解的比较清楚,但是由于Java的一切对象都是在堆上,因此有时候可能反而会比较迷惑,比如:
为什么要分堆和栈?
堆和栈的区别是什么?
为什么堆是线程共享的而栈不是?
很多懂一点Java的人甚至是懂一点编程的人都知道内存一般分为堆和栈,栈由系统进行关系,而堆由程序员自己管理,...balabala,基本任何一本语言基础书都会提到这些特点,但是你有想过为什么吗?
为什么要分堆和栈
之所以要区分堆和栈,是由于程序需要两种不同特性的内存形似而确定的。在C++中,新建一个对象有两种方式,静态分配和动态分配,
静态分配
一般来说,静态分配用于初始化已知对象大小的时候,比如int a[10];
如果我们能够确定这个数组是10个,我们可以使用这种方式。这种方式所需要的内存在编译期间即可确定,因此操作系统便可以预先确定所指定大小内存给变量,并且可以在变量生命周期结束后自动释放。
动态分配
然而在某些场景下,可能需要根据某些情况来申请内存,比如int* a =new int[count];
而变量count
可能就来自于某个配置文件或者用户手动输入的值。这个时候操作系统就无法再预先确定内存大小,并且不执行到new int[count]
这一行代码的时候,是无法知道所要分配的内存大小,因此操作系统分出一块内存,用来进行动态分配。并且规定,动态分配的内存需要由客户端自行管理。
Java 中的堆
由于JVM规范中规定,JVM中的一切对象都存储在堆上(内存逃逸除外)。因此在Java中并不存在对象的静态分配,因此堆和栈的来源看似就非常理所当然。但是要明白,在操作系统中,堆和栈的出现的缘由。
堆和栈的区别
知道了为什么要区分堆和栈,再来看看堆和栈的区别。
-
堆是运行时确定内存大小,而栈在编译时即可确定内存大小
理由便是第一节中提到的,这是区分堆和栈的初衷
-
堆内存由用户管理(Java中由JVM管理),栈内存会被自动释放
-
栈实现方式采用数据结构中的栈实现,具有(LIFO)的顺序特点,堆为一块一块的内存
-
栈由于其实现方式,在分配速度上比堆快的多。分配一块栈内存不过是简单的移动一个指针
-
在JVM中,栈不会被程序员直接使用,程序员操作的一般都是堆。
-
栈为线程私有而堆为线程共享
虽然堆和栈有这么多的区别,但是这些区别都是由于操作系统而决定的,在硬件上,他们本质都是RAM
为什么堆是线程共享的而栈不是?
上面最后一点提到了栈为线程私有而堆为线程共享。这是为什么呢???
其实很简单,为了解决一个问题:线程间通信。
想要实现线程间通信,目前有两种方法:
- 消息传递
- 共享内存
共享内存便是我们所说的将堆设置为线程间共享的,这样我们能够通过堆中的对象实现数据共享,这样便使得其他线程能够知道某个线程修改了某个数据。但是这样带来的问题可能就有线程安全问题等,但是这样做的优势便在于速度更快和节约内存,Java,C#等使用这种方式
消息传递是每个线程都私有自己的数据空间,当需要线程通信的时候,便需要一个线程显示的给另外一个线程发送具体的消息,这样做的能够让多线程更加安全,但是私有的线程空间和消息传递带来的是需要给内个线程都拷贝相同的对象,变量等,并且可能会带来效率问题。而Erlang和JoCaml便是使用消息传递式线程通信。
尊重劳动成功,转载注明原创
参考文章:
Why do threads share the heap space?
What’s the difference between a stack and a heap?
What and where are the stack and heap?
如果觉得写得不错,欢迎关注微信公众号:逸游Java ,每天不定时发布一些有关Java进阶的文章,感谢关注