“堆”,"栈","堆栈"的区别及部分应用

Posted ltyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了“堆”,"栈","堆栈"的区别及部分应用相关的知识,希望对你有一定的参考价值。

栈又名堆栈,“堆”和"栈"的概念要从数据结构、内存分配这两个方面来看。

数据结构中,栈(stack)是一种“后进先出”的存储结构。第一个进栈的为栈底,最后一个进栈的为栈顶。出栈从栈顶开始顺序进行。(我觉得在数据结构中就叫栈,这样比较清楚)
在实际编程中,可以通过两种方式来实现:使用数组的形式来实现栈,这种栈也称为静态栈;使用链表的形式来实现栈,这种栈也称为动态栈。

堆(heap)是一种特殊的完全二叉树。其中,节点是从左到右填满的,并且最后一层的树叶都在最左边(即如果一个节点没有左儿子,那么它一定没有右儿子);每个节点的值都小于(或者都大于)其子节点的值(最小堆或者最大堆)。
相对于栈的“先进后出”特性,堆则是一种经过排序的树形数据结构,常用来实现优先队列等。

内存分配中的堆和栈:

内存分配方式不外乎包含如下三种形式:
1.从静态存储区域分配,
2.在栈上分配,
3.从堆上分配,也被称为动态内存分配。

在java中,每个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个JVM内存堆区。进程所创建的所有类的实例(也就是对象)或数组(指的是数组的本身,不是引用)都放在堆中,并由该进程所有的线程共享。进程中每一个线程在JVM内存中有一个自己私有的栈区。虽然Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配的,也就是说在建立一个对象时在堆和栈中都分配内存,在堆中分配的内存实际存放这个被创建的对象的本身,而在栈中分配的内存只是存放指向这个堆对象的引用而已。局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收。
堆是程序运行时申请的动态内存,而栈是指一种使用堆的方法(所以栈又名堆栈,我觉得内存分配中叫堆栈比较好)

JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method,也叫静态区)。
堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息(class的目的是得到操作指令) ;
2.jvm只有一个堆区(heap),且被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身和数组本身;
为什么叫“堆”,我觉得,堆区和数据结构中的二叉树堆的性质有类似的地方,如:内存区域不连续的、可随意存取的、地址链表的遍历方向是由低地址向高地址进行的等。

栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型本身和自定义对象的引用;
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问;
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令);
为什么叫“栈”,我觉得,首先这是一块连续的内存区域(其地址的增长方向是由高向低地址进行的,最大容量一般由系统规定,相对于较小)。另外虽然内存读取是可以随意的,但C中在函数调用时,第一个存入的是主函数中函数调用后的下一条指令的地址,然后是函数的各个参数,类似入栈操作,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,清除内存类似出栈,局部变量先出栈,然后是参数,最后指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。与C不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

方法区(静态区):
1.被所有的线程共享,方法区包含所有的class(class是指类的原始代码,要创建一个类的对象,首先要把该类的代码加载到方法区中,并且初始化)和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
启动一个Java进程,这个进程首先会读取类的类信息存放到方法区中。

“栈”是一个重要的数据结构,“后进先出”这种特性有着广泛的应用,如递归调用、括号匹配等是常用的例子。
OSI模型就是一个七层的协议栈。协议栈是指网络中各层协议的总和,其形象的反映了一个网络中数据传输的过程:由上层协议到底层协议,再由底层协议到上层协议。

通信协议的知识点下篇再复习。。。

 

以上是关于“堆”,"栈","堆栈"的区别及部分应用的主要内容,如果未能解决你的问题,请参考以下文章

有关堆内存和栈内存的问题

理解 "栈" "队列","堆"(后进先出)

java中 关于常量池 栈内存 堆内存

"=="和 equals 方法究竟有什么区别?

java中的String常量是存放在栈中还是堆中?

Java中关于String对象引用的问题?