c#浅拷贝/深拷贝和内存分配

  1. 值类型和引用类型
    概念:值类型直接存储其值,而引用类型存储对其值的引用。
    引用类型:基类为Objcet
    值类型:均隐式派生自System.ValueType
    • 值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
    • 引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
    • 值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。
    • 引用类型的对象总是在进程堆中分配(动态分配)。
  2. 内存分配
    CLR内存分配区域:线程堆栈(栈)、GC堆、大对象堆LOH

一、线程堆栈(栈)
用于分配值类型实例。栈由操作系统进行管理,不受GC管理,当值类型不在其作用域(主要是指其所在函数内)时,其所占栈空间自动释放。栈的执行效率是非常高的。

二、GC堆(堆)
用于分配小对象实例。所谓小对象就是大小小于85000字节的实例对象。GC堆分三代垃圾进行管理,当进行GC操作(垃圾回收)时,垃圾收集器会对GC堆进行压缩回收。具体的GC操作(略)。

三、大对象堆(LOH)
用于分配大对象实例。大对象就是大小小于85000字节的实例对象。大对象分配在LOH上,不受GC控制,不会被压缩,只有在完全GC回收时才会被回收。

注意

a.栈的分配是向低地址扩展,而堆的分配是向高地址扩展。
b.值参数与引用参数的本质,值参数是对栈中数据的拷贝,引用参数则是对栈地址的引用。当值参数为某引用对象时,可以改变该引用对象某些值,但不能将值改变成新对象的地址。
c.堆中的对象都有同步块索引(占4个字节)、类型句柄(占4个字节)
d.静态字段、静态方法不和方法所分配的方式与区域—–方法表
e.值类型变量的值存放在变量内部,而引用类型变量的值存放在堆上,变量本身存放一个指向堆中的值的引用。

    public class RefrenceAndValueType
    {
        public static void Run()
        {
            Struct_ValueType sValueType1 = new Struct_ValueType();
            sValueType1.IntValue = 1;
            sValueType1.StringObj = "1";
            sValueType1.class_T = new Class_T();

            Struct_ValueType sValueType2 = sValueType1;

            sValueType2.IntValue = 2;
            sValueType2.StringObj = "2";
            sValueType2.class_T.INT_Value = 2;
            sValueType1.class_T.String_Name = "李四";

            Console.WriteLine(string.Format("sValueType1.IntValue: {0} ; sValueType2.IntValue: {1} ", sValueType1.IntValue, sValueType2.IntValue));
            Console.WriteLine(string.Format("sValueType1.StringObj: {0} ; sValueType2.StringObj: {1} ", sValueType1.StringObj, sValueType2.StringObj));
            Console.WriteLine(string.Format("sValueType1.class_T.INT_Value: {0} ; sValueType2.class_T.INT_Value: {1} ", sValueType1.class_T.INT_Value, sValueType2.class_T.INT_Value));
            Console.WriteLine(string.Format("sValueType1.class_T.String_Name: {0} ; sValueType2.class_T.String_Name: {1} ", sValueType1.class_T.String_Name, sValueType2.class_T.String_Name));


            Class_Refrence cRefrence1 = new Class_Refrence();
            cRefrence1.IntValue = 1;
            cRefrence1.StringObj = "1";
            cRefrence1.StructValue = new Struct_ValueType();
            cRefrence1.StructValue.IntValue = 1;
            cRefrence1.StructValue.StringObj = "1";

            Class_Refrence cRefrence2 = cRefrence1;

            cRefrence2.IntValue = 2;
            cRefrence2.StringObj = "2";
            cRefrence2.StructValue.IntValue = 2;
            cRefrence2.StructValue.StringObj = "2";

            Console.WriteLine(string.Format("cRefrence1.IntValue: {0} ; cRefrence1.IntValue: {1} ", cRefrence1.IntValue, cRefrence2.IntValue));
            Console.WriteLine(string.Format("cRefrence1.StringObj: {0} ; cRefrence1.StringObj: {1} ", cRefrence1.StringObj, cRefrence2.StringObj));

            Console.WriteLine(string.Format("cRefrence1.StructValue.IntValue: {0} ;  cRefrence2.StructValue.IntValue: {1} ", cRefrence1.StructValue.IntValue, cRefrence2.StructValue.IntValue));
            Console.WriteLine(string.Format("cRefrence1.StructValue.StringObj: {0} ; cRefrence2.StructValue.StringObj: {1} ", cRefrence1.StructValue.StringObj, cRefrence2.StructValue.StringObj));
        }
    }

    public class Class_T
    {
        public int INT_Value = 1;
        public string String_Name = "张三";
    }

    public struct Struct_ValueType
    {
        public int IntValue;
        public string StringObj;

        public Class_T class_T;
    }

    public class Class_Refrence
    {
        public int IntValue;
        public string StringObj;
        public Struct_ValueType StructValue;
    }

这里写图片描述
值类型是完全拷贝,引用类型是对地址的拷贝。


*
3. 字符串的内存分配与驻留池(string.Intern)
string在初始化后不可变,每次操作都会创建新的对象重新分配内存。在赋值为常量字符串时,相同常量字符串值的string地址一致。可通过string.Intern(string)检查是否有常量字符串值,有则返回常量字符串值。
4. 深拷贝和浅拷贝
深拷贝:指的是拷贝一个对象时,不仅仅把对象的引用进行复制,还把该对象引用的值也一起拷贝。这样进行深拷贝后的拷贝对象就和源对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
浅拷贝:指的是拷贝一个对象时,仅仅拷贝对象的引用进行拷贝,但是拷贝对象和源对象还是引用同一份实体。此时,其中一个对象的改变都会影响到另一个对象。
浅拷贝实现: object.MemberwiseClone()
.NET中值类型默认是深拷贝的,而对于引用类型,默认实现的是浅拷贝。
深拷贝实现:反射(当有互相引用时可能会有问题)、序列化/反序列化(xml/二进制/DataContractSerializer)、表达式树
参考:
C# 浅析值类型与引用类型的内存分配
C#中字符串的内存分配与驻留池
C#内存分配学习
深入解析深拷贝和浅拷贝
C#的两种类据类型:值类型和引用类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值