黑马程序员技术交流社区

标题: 关于栈与堆的问题 [打印本页]

作者: 李泽霖    时间: 2012-2-7 09:52
标题: 关于栈与堆的问题
今天看了数据结构,还是对关于对于栈与堆的概念有点模糊,求精确回答
作者: 易伟    时间: 2012-2-7 09:59
栈与堆都是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, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
String是一个特殊的包装类数据。可以用:
String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。
比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。
因 此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
另 一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的 对象。只有通过new()方法才能保证每次都创建一个新的对象。
由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

作者: 王文龙    时间: 2012-2-7 10:02
简单理解为:
栈:存放基本数据类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中.栈中数据可以自动释放.
堆:存放用new产生的数据.堆中数据若无变量引用会成为垃圾,有垃圾回收机制处理.

eg:
Person p=new Person("webb",34);
new产生的对象new Person("webb",34)存放于堆,
而它的引用变量P存放于栈,
这个P就相当于为堆中的数据起了个名字.

栈中的变量指向堆中变量,相当于指针.


作者: 陈时峰    时间: 2012-2-7 10:23
这是我在《java编程思想》中看到的关于堆和栈的介绍
1,栈(stack)。位于“常规内存区(general random-access memory area)”里,
处理器可以通过栈指针(stack pointer)对它进行直接访问。栈指针向下移就创建了
新的存储空间,向上移就释放存储空间。这是仅次于寄存器的最快,最有效率的分配
内存的方法。由于java编译器必须生成能控制栈指针上移和下移的代码,所以程序编译
的时候,那些将被存储在栈中的数据的大小和生命周期必须是已知的。这使得程序的灵
活性受到了限制,所以尽管java把某些数据—特别是对象的引用存放在栈里,但对象本身
并没有放在栈中。
2,堆(heap)。这是一段“多用途的内存池”(genaral-purpose pool of memory,也
在内存里面),所有java对象都保存在这里。同栈不同,堆的优点是,分配空间的时候,
编译器无需知道该分配多少空间,或者这些数据会在堆里呆多长时间。因此使用堆的空间
会比较灵活。只要你想创建对象,用new就行,程序执行的时候自会在堆里分配空间。当然
你得为这种灵活付出代价,分配堆得存储空间要比分配栈的慢一些。


作者: 孙汇川    时间: 2012-2-7 10:59
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, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

String是一个特殊的包装类数据。可以用:
String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。

String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。


因此用第一种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的 对象。只有通过new()方法才能保证每次都创建一个新的对象。
由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。


这里有更加详细的关于堆栈区别的解释:http://www.newsmth.net/pc/pccon.php?id=2206&nid=338138
作者: 张青峰    时间: 2012-2-7 11:41
绝大数情况下,java程序(方法、变量、对象)驻留在内存中的栈和堆上。

栈(堆栈):驻留于常规RAM(随机访问存储器)区域,但可通过它的“堆栈指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。
        创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java数据要保存在堆栈里——特别是对象句柄,但Java对象并不放到其中。

堆:一种常规用途的内存池(也在RAM区域),其中保存了Java对象。和堆栈不同,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!

总结:
1.对象在栈上
2.局部变量在堆上
3.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程式员不能直接地设置栈或堆。
4. 栈的优势是,存取速度比堆要快,仅次於直接位於CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

希望对你有帮助
作者: 王_涛    时间: 2012-2-7 11:46
1.栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
   栈中一般存放一些基本类型共有8种,即int, short, long, byte, float, double, boolean, char和对象的引用。

2.堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

作者: 秦碧    时间: 2012-2-7 12:12
以上各位大多都在说数据在栈内存和堆内存中的存放的问题
谈谈我对栈数据结构在栈内存中的使用的看法吧
个人理解 见笑
栈: 类似把数据放到一个箱子里,后放入的数据会被先拿出来,因为后放入的数据压在上面;
(先将main函数压入栈,然后main函数调用一个method_1 ,则method_1压入栈,处理完method_1,method_1弹出栈,继续运行main函数)

对于堆
我只是知道堆在数据结构中 是一个优先队列(把一堆数据想成一群人,每个人有自己的岁数,可以让最年少的优先出列)比较适合存放数据吧
而对象的数据是如何存在于堆内存中的 我也不是很清楚。。。
作者: 荣凯旋    时间: 2012-2-7 12:49
楼主看看,这个问题在这期中已有很明确的回答啦
作者: 李泽霖    时间: 2012-2-7 14:00
荣凯旋 发表于 2012-2-7 12:49
楼主看看,这个问题在这期中已有很明确的回答啦

灰常给力 ,明白了
作者: 最初的理想    时间: 2012-2-7 18:45
1.寄存器

最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制。

2. 栈

存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)

3. 堆

存放所有new出来的对象。

4. 静态域

存放静态成员(static定义的)

5. 常量池

存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储
硬盘等永久存储空间
这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
如以下代码:
1.String s1 = "china";  2.String s2 = "china";  3.String s3 = "china";  4.String ss1 = new String("china");  5.String ss2 = new String("china");  6.String ss3 = new String("china"); 对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。
如以下代码:
1.int i1 = 9;  2.int i2 = 9;  3.int i3 = 9;  4.public static final int INT1 = 9;  5.public static final int INT2 = 9;  6.public static final int INT3 = 9;  对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。
成员变量存储在堆中的对象里面,由垃圾回收器负责回收。
如以下代码:
1.class BirthDate {  2.private int day;  3.private int month;  4.private int year;  5.public BirthDate(int d, int m, int y) {  6.day = d;  7.month = m;  8.year = y;  9.}  10.省略get,set方法…… }  11.public class Test{ public static void main(String args[]){  12.int date = 9;  13.Test test = new Test();  14.test.change(date);  15.BirthDate d1= new BirthDate(7,7,1970);  16.}  17.public void change1(int i){ i = 1234;  18.} 对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:
1. main方法开始执行:
1.int date = 9;  date局部变量,基础类型,引用和值都存在栈中。
2. test为对象引用,存在栈中,对象(new Test())存在堆中。
1.Test test = new Test();  3.
1.test.change(date);  i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。
4.
1.BirthDate d1= new BirthDate(7,7,1970);  d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。
5.main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收。
希望通过以上内容的介绍,能够给你带来帮助。
作者: 最初的理想    时间: 2012-2-7 18:50
秦碧 发表于 2012-2-7 12:12
以上各位大多都在说数据在栈内存和堆内存中的存放的问题
谈谈我对栈数据结构在栈内存中的使用的看法吧
个人 ...

数据结构里的堆栈是数据的组织方式,和队列一样,不过堆栈里的数据是先进后出,堆栈只有一端能放入和取出数据像一个瓶子一样,队列是先进先出,像一个管道,一端放入数据一端取出数据
作者: 【专】【属】    时间: 2012-2-7 19:35
个人感觉:没有必要太清楚了,只要知道,栈是存变量的,而堆是存new对象的。




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