`

堆栈的理解

 
阅读更多

堆(heap)的数据结构是完全二叉树
新增示意图

删除示意图

先进先出,这种结构适合做存储。

堆是存储的单位,而栈是运行时的单位。

栈(stack)是后进先出,存储运行时的变量,即方法中的变量

代码中,越里层的变量,作用域越小,用完就释放,适合栈这种数据结构

 

栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么
放、放在哪儿。

 

栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。

 

面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。当我们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。

 

堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。

 

程序运行永远都是在栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接
传对象本身。

 

 

Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现
java.lang.StackOverflowError异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。

 

堆,顺序随意。栈,后进先出(Last-In/First-Out)。

栈(操作系统):stack的空间由操作系统自动分配和释放,由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈
栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放

堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些

 

 

 

 

1.heap是堆,stack是栈。

2.stack的空间由操作系统自动分配和释放,heap的空间是手动申请和释放的,heap常用new关键字来分配。

3.stack空间有限,heap的空间是很大的自由区。

在Java中,

若只是声明一个对象,则先在栈内存中为其分配地址空间,

若再new一下,实例化它,则在堆内存中为其分配地址。

4.举例:

数据类型 变量名;这样定义的东西在栈区。

如:Object a =null; 只在栈内存中分配空间

new 数据类型();或者malloc(长度);    这样定义的东西就在堆区

如:Object b =new Object(); 则在堆内存中分配空间


Stack.   This   lives   in   the   general   RAM   (random-access   memory)   area,   but   has   direct   support   from   the   processor   via   its   stack   pointer.   The   stack   pointer   is   moved   down   to   create   new   memory   and   moved   up   to   release   that   memory.   This   is   an   extremely   fast   and   efficient   way   to   allocate   storage,   second   only   to   registers.   The   Java   compiler   must   know,   while   it   is   creating   the   program,   the   exact   size   and   lifetime   of   all   the   data   that   is   stored   on   the   stack,   because   it   must   generate   the   code   to   move   the   stack   pointer   up   and   down.   This   constraint   places   limits   on   the   flexibility   of   your   programs,   so   while   some   Java   storage   exists   on   the   stack   ?in   particular,   object   handles   ?Java   objects   are   not   placed   on   the   stack.   

Heap.   This   is   a   general-purpose   pool   of   memory   (also   in   the   RAM   area)   where   all   Java   objects   live.   The   nice   thing   about   the   heap   is   that,   unlike   the   stack,   the   compiler   doesn 't   need   to   know   how   much   storage   it   needs   to   allocate   from   the   heap   or   how   long   that   storage   must   stay   on   the   heap.   Thus,   there 's   a   great   deal   of   flexibility   in   using   storage   on   the   heap.   Whenever   you   need   to   create   an   object,   you   simply   write   the   code   to   create   it   using   new   and   the   storage   is   allocated   on   the   heap   when   that   code   is   executed.   And   of   course   there 's   a   price   you   pay   for   this   flexibility:   it   takes   more   time   to   allocate   heap   storage.  


Java中堆内存与栈内存分配浅析
http://www.iteye.com/topic/941682
Java把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。 

  堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。 

  这也是Java比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针! 

  java中内存分配策略及堆和栈的比较 

  1 内存分配策略 

  按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 

  静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求. 

  栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。 

  静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放. 

  2 堆和栈的比较 

  上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈: 

  从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的: 

  在编程中,例如C/C++中,所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个"大小多少"是在编译时确定的,不是在运行时. 

  堆是应用程序在运行的时候请求操作系统分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用 new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~). 

  3 JVM中的堆和栈 

  JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。 

  我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的. 

  从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。 

  每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。 

  Java 中的堆和栈 

  Java把内存划分成两种:一种是栈内存,一种是堆内存。 

  在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 

  当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 

  堆内存用来存放由new创建的对象和数组。 

  在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 

  在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。 

  引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。 

  具体的说: 

  栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 

  Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。 

  栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。 

  栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义: 

  int a = 3; 

  int b = 3; 

  编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量 

  • 大小: 13.6 KB
分享到:
评论

相关推荐

    计算机有关堆栈的理解

    计算机堆栈理解 计算机堆栈是计算机原理中非常重要的一部分,对于程序员来说非常重要。堆栈是用来存储临时变量,函数传递的中间结果,是操作系统维护的,对于程序员是透明的。下面我们将通过一个小例子来详细解释栈...

    单片机地址空间,堆栈理解

    "单片机地址空间与堆栈理解" 单片机地址空间是指单片机中存储器的组织方式,包括程序存储器、内部数据存储器、SFR、位地址空间和外部数据存储器。其中,程序存储器用于存储单片机的程序代码,内部数据存储器用于...

    堆栈初级理解应用

    ### 堆栈初级理解应用 #### 最简单堆栈简单介绍与初级理解和应用 本文将对堆栈(Stack)的基本概念、工作原理及其简单的Java实现进行详细的解释,并通过一个具体的编程示例来帮助读者更好地理解堆栈的工作机制。 ...

    关于单片机堆栈指针的理解

    ### 关于单片机堆栈指针的理解 #### 一、单片机堆栈指针的概念与作用 在单片机编程中,堆栈指针(Stack Pointer, SP)是一个非常重要的寄存器,用于指示堆栈(Stack)的顶部位置。堆栈是一种特殊的线性数据结构,...

    labview堆栈实现及堆栈状态机

    LabVIEW是一种图形化编程语言,由美国国家仪器公司(NI)开发,广泛应用于测试测量、自动化和控制系统领域。在LabVIEW编程中,堆栈是一种重要的...理解并熟练掌握堆栈和状态机的概念对于提升LabVIEW编程技能至关重要。

    单片机与DSP中的单片机地址空间,堆栈理解

    data –可寻址片内ram 0x00-0x7f  bdata—可位寻址片内ram  idata—可寻址片内ram,允许访问全部内部ram 0x00-0xff  padata—分页寻址访问片外ram  xdata—可寻址片外ram 0x0000- 0xffff ...

    dongzuoji.zip_labview做堆栈_labview有堆栈吗

    通过深入研究和实践这个“堆栈动作机”,你不仅可以掌握LabVIEW中的堆栈实现,还能提升在LabVIEW中的编程技巧和对数据结构的理解。这对你在进行复杂系统开发,尤其是在需要高效数据管理和控制逻辑的场合,都将...

    易语言汇编动态堆栈调用

    1. **堆栈布局**:理解堆栈的生长方向,通常是向下生长,以及如何通过ESP(栈指针)寄存器跟踪堆栈顶部。 2. **函数调用约定**:了解不同的函数调用约定,比如stdcall、cdecl等,它们决定了参数如何压入堆栈,以及...

    堆栈源代码实现

    本文将详细解析标题为“堆栈源代码实现”的资源,旨在帮助你理解和实现自己的堆栈功能。堆栈在计算机科学中扮演着多种角色,包括函数调用、表达式求值、内存管理等。 堆栈的基本操作通常包括: 1. **压入(Push)*...

    STM32 堆栈检测示例

    STM32是一款基于ARM Cortex-M内核的微控制器,广泛应用于嵌入式系统设计。堆栈检测在STM32开发中是一项重要的任务,它能够...同时,理解并运用这些检测方法,能帮助开发者更好地管理和优化资源,提升整体的项目性能。

    践踏堆栈攻防总结

    总的来说,践踏堆栈攻击是信息安全领域的一个重要话题,理解和防范此类攻击对于保护系统免受恶意攻击至关重要。开发者应遵循安全编码规范,使用安全的编程语言,并结合各种防御技术,以减少栈溢出漏洞的出现。同时,...

    .NET-BenDemystifier高性能的堆栈跟踪理解

    本文将深入探讨如何理解和利用高性能的堆栈跟踪,以提高错误日志的效率,以及在代码分析和度量中的应用。 堆栈跟踪是当程序抛出异常或通过其他方式触发时,系统记录的一系列方法调用的回溯。它显示了执行流程从发生...

    堆栈操作_StackSamplt

    在计算机科学中,堆栈(Stack)...无论你是初学者还是经验丰富的开发者,理解堆栈操作及其应用场景都将极大地提升你的编程能力。通过StackSamplt,你可以亲自动手,加深对堆栈操作的理解,从而更好地应用到实际项目中。

    堆栈的模拟实现|堆栈的工作过程与应用

    在计算机科学中,堆栈是一种非常基础且重要的数据结构,它遵循“后进先出”(LIFO)的原则。本课程设计的目标是通过编程模拟堆栈的实现...理解和掌握堆栈的工作原理及其在程序设计中的应用,对于提升编程能力尤其重要。

    易语言申请进程堆栈内存

    进程的堆栈内存管理是程序员必须理解和掌握的关键技能,特别是在低级编程或者系统级编程中。易语言,一种面向对象、简单易学的中文编程语言,也提供了对进程堆栈内存的操作支持。本文将详细解析"易语言申请进程堆栈...

    数据结构-顺序堆栈

    通过阅读和理解源码,你可以深入学习到C语言中的指针操作、动态内存管理和数据结构实现技巧。 总结来说,这个“数据结构-顺序堆栈”项目旨在通过C语言实现一个灵活、高效且可扩展的堆栈数据结构。通过泛型编程,...

    java 堆栈的演示程序

    在这个"java 堆栈的演示程序"中,我们可能会深入理解堆栈的工作原理以及它在运行jsp程序时的角色。源代码设计将帮助我们直观地看到如何在实际编程中使用堆栈。 首先,我们要明白堆栈是Java中用于存储局部变量、方法...

    用堆栈实现的计算器(基于C++的程序)

    对于不会用堆栈和对堆栈理解不是很深入深入的初学者来说是一个不容错过的资料。拿来和大家共享一下!

    vC 堆栈 异常处理

    在编程领域,异常处理是确保程序健壮性的重要机制,特别是在使用C++这种语言时,理解和掌握堆栈和异常处理的原理至关重要。vC(可能是VC++,即Visual C++的简称)是Microsoft开发的一个集成开发环境,它包含了对C++...

Global site tag (gtag.js) - Google Analytics