代码改变世界

值类型与引用类型初窥

2010-11-26 13:32  Shawn.Cheng  阅读(148)  评论(0编辑  收藏  举报

没有时间写废话,直接上测试代码。

 

    class TestAddressRef

    {

        public int num;

    }

 

 

 

 

class Program

    {

        static void Main(string[] args)

        {

            TestAddressRef tar1=new TestAddressRef();

            tar1.num = 1;

            TestAddressRef tar2 = tar1;

            TestAddressRef tar3=new TestAddressRef();

            TestAddressRef tar4 = tar3;

            tar3.num = 3;

            tar3 = tar1;

            Console.WriteLine("tar1的值{0}/ntar2的值{1}/ntar3的值{2}/ntar4的值{3}/n", tar1.num, tar2.num, tar3.num,tar4.num);

        }

 

 

输出为:

 

tar1的值1

tar2的值1

tar3的值1

tar4的值3

 

 

我是这样理解的:

new 一个对像后,在堆内分配一个该对象的存储空间。在栈内为该标志符赋值为 堆内该对象的首地址,并记录对象类型(空间什么的)。

如这句话TestAddressRef tar1=new TestAddressRef();

而对于TestAddressRef tar2;相当于仅在栈内分配了一个空间,保存实际对象的地址为null(即该对象未在队内分配空间)。当有 tar2 = tar1时,将tar1栈内的值给了tar2,这样,tar2也指向了与1相同的堆内对象。

3 和4 就比较有意思了,3申请了新空间后,4也得到这个地址,然后3栈内保存的地址又被1赋值,即3有指向了1所指向的堆空间,也就是放弃了原来申请的堆空间的控制(4控制着该堆内的对象,4这里起到了捕获3遗漏空间的作用)。就出现了如上结果。

我有个疑问,当tar3 放弃了对原堆空间的控制后,转向1,会不会产生内存泄露了呢(不用4捕获的情况下)???

因为编译器无法获知原来tar3申请的空间什么时候会失效(其实,如果不是我们用tar4来捕获,到最后tar4超出了它的作用域,连我们自己也不知道该空间内保存的值什么时候才会不被用到),编译器貌似就难以在适时的时候进行垃圾回收了!????我暂时还没想明白,应该牵涉到垃圾回收的机制吧,等我想明白了再来补上。

恩,就这样。

欢迎提出不同的观点。

 

###


补1:

     (1) 不是所有new一下就是引用类型,如struct类型。

             定义个结构类型Mystruct, 如果写Mystruct ms=new Mystruct();结构实例对象仍然是在栈内分配的。new一下,编译器会认为实例已初始化。如果没有new,认为实例的所有字段没有初始化,不可访问使用,编译错误。

#####2011-10-12

或许我们根本不用担心这个问题,C#垃圾回收应该就是干这个事的。至于什么时候才回收,现在暂时还不是很清楚。