黑马程序员技术交流社区

标题: 堆和栈的区别 [打印本页]

作者: 黑飞马    时间: 2013-10-29 16:49
标题: 堆和栈的区别
本帖最后由 黑飞马 于 2013-10-31 15:55 编辑

经常看到值类型存储在栈上 ,引用类型存储在堆上 ,这个到底是什么意思呀?
作者: 李洋    时间: 2013-10-29 17:07
1.栈内存是直接从你的物理内存上被系统划分出来的一块特定区域。栈空间可以看做是系统的一个缓存内存空间,空间很小。在windows操作系统下大小是2M。因为栈的空间是连续的,程序寻址很快,所以栈里的内存读写效率是比堆要高的。栈内存由系统内核自动管理,创建时可直接由程序员申请,超出作用域后该块内存自动被标为可用内存,以便接下来新的数据再次使用。在java中所有的引用变量和基本数据类型都在栈中,因为这些类型数据量比较小,读写很频繁,所以放在是比较小的栈中不会太拥挤,同时可以提高效率。
2.堆内存是你电脑所有可利用内存的整合,其中包括物理内存,虚拟内存。因此堆内存是不连续的,当须要使用堆内存时系统会查找所有堆空间中一块大小够放你申请数据的地方然后拿出来用。所以堆内数据在读写的时候,都须要系统寻址比较长的时间来查找相应的位置,所以速度比栈要慢一些。但是堆的好处是很大。你所有的电脑可用内存都在堆内存的范围内。所有用new关键词建立出来的东西都是在堆中的,java中有堆内存回收机制,所以回收也是自动的,不用程序员管理。Integer num = new Integer(888);其中num是一个引用,所以他在栈空间中,而888这个数是new出来的。所以在堆中开了一块大小为4*8 =32bit的地方用来放888这个数 int num = 5;因为没使用new所以仅仅只是在栈中开了一块大小为32bit的地方放这个5,然后把这个地方的地址给了num保存。
作者: 凌晨丶草未眠    时间: 2013-10-29 17:36
内存分栈和堆;
值类型存储在栈,先进后出,
引用类型存储在堆,当实例化一个对象时,在堆存储该对象,当该对象消亡才从堆中清除掉
作者: 陈福军    时间: 2013-10-29 19:59
本帖最后由 陈福军 于 2013-10-29 20:04 编辑

栈,是一个内存数组,是一个LIFO(last in  first out  后进先出)的数据结构。
堆,是一块内存区域,用于储存类型的数据对象

下面是一个例子和图像来区分栈与堆的不同之处
    class Program
    {
        static void Main(string[] args)
        {
            Person person1 = new Person();
            person1.Name = "tom";
            Person person2= new Person();
            person2.Name = "jack";
            Person person3 = new Person();
            person3.Name = "李小龙";
        }
    }
    class Person
    {
        public string Name { set;get;}
        public int Age { set; get; }
    }
}


栈与堆的关系.png (25.84 KB, 下载次数: 43)

栈与堆的区别

栈与堆的区别

作者: 陈福军    时间: 2013-10-29 20:03
这样的图解不知楼主能否看懂
作者: 马晓平    时间: 2013-10-30 00:17
理解堆与栈对于理解.NET中的内存管理、垃圾回收、错误和异常、调试与日志有很大的帮助。垃圾回收的机制使程序员从复杂的内存管理中解脱出来,虽然绝大多数的C#程序并不需要程序员手动管理内存,但这并不代表程序员就无需了解分配的对象是如何被回收的,在一些特殊的场合仍需要程序员手动进行内存管理。
在32位的处理器上,每个进程的虚拟内存为4GB,.NET会在这4GB的内存块中开辟出3块内存,分别作为栈、托管堆、和非托管堆
堆(heap):
堆是从下往上分配,所以已用的空间在自由空间下面,C#中所有引用类型的对象分配在托管堆上,托管堆在内存上是连续分配的,并且内存对象的释放受垃圾收集机制的管理,效率相对于栈来说要低的多。
栈(stack):
栈是自上向下进行填充,即由高内存地址指向低内存地址,并且内存分配是连续的,C#中所有的值类型和引用类型的引用都分配在栈上,栈根据后进先出的原则,依次对分配和释放内存对象。
对象内存的分配与销毁:
当一个类的实例对象创建的时候,这个对象的不同成员按类别被分配到了不同的内存区域,值类型和引用类型的指针被分配到了栈上,引用类型的实例对象被分配到了托管堆上,静态成员被分配到了全局数据区。此时栈上的指针会指向堆上的对象。当对象使用完以后,引用和实际对象的联系就会断开,从而从而使对象冬眠。因为栈具有自我维护性,它的内存管理可以通过操作系统来完成,而此时堆上的冬眠对象就需要通过垃圾回收器(GC)使用一定的算法来进行回收,释放对象所占据的内存。
C#中的深拷贝与浅拷贝
深拷贝:又称深度克隆,它完全是新对象的产生,不仅复制所有的非静态值类型成员,而且复制所有引用类型成员的实际对象。(即栈上和堆上的成员均进行复制)
浅拷贝:又称影子克隆,只复制原始对象中的所有的非静态的值类型成员和所有引用类型成员的引用,就是说,原始对象和新对象共享所有引用类型成员的对象实例。(即只复制栈上的成员)
注:不管是深拷贝还是浅拷贝,都不会复制全局数据区的成员,因为全局数据区的成员是静态成员,它属于某一个类,并不属于类的实例对象,因此无法复制。
C#中的深拷贝可以通过实现ICloneable接口来实现,但是在不是必须实现ICloneable接口的情况下,应避免类型继承ICloneable接口。因为这样做将强制所有的子类必须实现ICloneable接口,否则子类的新成员将不能被类型的深拷贝所覆盖
作者: 追溯客    时间: 2013-10-31 07:29
如问题得到解决,请及时把分类修改为"已解决",这样版主才能给你加分!黑马有你更精彩!
作者: 特洛伊    时间: 2013-10-31 10:57
栈区是用来存放一些可执行的代码 命令,堆区是放一些数据,比如开辟一块内存空间。




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