黑马程序员技术交流社区

标题: 求教:栈内存与对内存的区别 [打印本页]

作者: 初艳春    时间: 2012-11-18 20:49
标题: 求教:栈内存与对内存的区别
本帖最后由 星星 于 2012-11-19 13:08 编辑

栈内存与堆内存 除了在数组的存储上有所差别,还有没有其他的区别?请说的具体一点。
作者: 刘腾    时间: 2012-11-18 21:19
原来总结过,希望对你有帮助http://bbs.itheima.com/thread-31137-1-2.html
作者: 奚华    时间: 2012-11-18 21:33
以下内容来自《java内存管理机制与jvm参数介绍》一书:

1、在函数中定义的一些基本类型的变量和对象的引用变量都在方法栈内存中分配(个人理解:如果你在方法中定义一个变量,例如,int a=10;那么a变量就被存到方法的栈中,存取a变量时用到出栈和入栈指令,你如果接触过C和汇编就会对方法或函数里的变量了解的深一点)。

2、堆用来存放由new创建的对象和数组。(个人理解:注意这里存的是对象本身,而不是对象的引用。堆的内存可以在运行时动态分配,是共享的)

3、在堆中创建一个数组或者对象后,还可以在栈中定义一个变量,让这一个变量的取值等于等于数组或对象在在堆内存中的首地址,栈中的这一个变量就成了这个数组或对象的引用变量

4、(个人理解:其实堆中存放的对象,不仅有new创建出来的,还有其他一些方法产生的,我们看一些例子:如下所示)
  1. String str1="acd";//在栈中查找“acd”是否存在,如果存在,则让str1指向它,如果不存在则在栈中创建"acd",并且将str1指向它
  2. String str2="acd";//同上

  3. System.out.println(str1==str2);//显示为true

  4. String str3=new String("acd");//在堆中new str3对象
  5. String str4=new String("acd");//在堆中new str4对象
  6. System.out.println(str3==str4);//false,new出来的对象放的内存地址是不同的
  7. System.out.println(str3.equals(str4));//true
  8. System.out.println(str3==str1);//false

  9. String hello ="Hello";
  10. String helloWorld1= hello+"World";
  11. Stirng helloWorld2=hello+"World";
  12. System.out.println(helloWorld1==helloWorld2);//false,这个例子我猜想helloWorld1和helloWorld2两个对象本身都位于堆中,是有不同地址的两个对象
  13. System.out.println(helloWorld1.equals(helloWorld2));//true
复制代码
4、java的堆是一个运行时数据区,类的对象从中分配空间,这些对象通过java中new、newarray、anewarray、multianewarray等指令建立

5、栈中变量超过了作用域或生存期就被自动释放,而堆中的对象有java垃圾回收器释放,堆可以动态扩展但速度较慢,栈速度较快,仅次于寄存器

6、栈中数据可以共享,比方说,定义了一个变量int a=5,那么再定义int b =5时,就可以是b指向a所指的变量(我的理解:java中String有一个字符串池,以及Integer数字为-127~128Iinteger对象都有这样的共享机制)
作者: 刘丽娜    时间: 2012-11-18 21:35
 Java把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

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

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

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

  1 内存分配策略

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

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

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

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

  2 堆和栈的比较

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

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

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

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


原文出自【比特网】,转载请保留原文链接:http://soft.chinabyte.com/database/407/11319907.shtml




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2