c#浅拷贝/深拷贝和内存分配
来源:互联网 发布:owncloud支持windows 编辑:程序博客网 时间:2024/06/06 18:57
- 值类型和引用类型
概念:值类型直接存储其值,而引用类型存储对其值的引用。
引用类型:基类为Objcet
值类型:均隐式派生自System.ValueType- 值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
- 引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
- 值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。
- 引用类型的对象总是在进程堆中分配(动态分配)。
- 内存分配
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#的两种类据类型:值类型和引用类型
- c#浅拷贝/深拷贝和内存分配
- C/C++ 堆内存分配 浅拷贝 深拷贝
- 继承之动态内存分配&深拷贝浅拷贝
- C#的浅拷贝和深拷贝
- 深拷贝 浅拷贝 内存零拷贝
- C# 深拷贝/浅拷贝
- C# 深拷贝 浅拷贝
- C# 深拷贝浅拷贝
- 浅拷贝和深拷贝
- 浅拷贝和深拷贝
- 浅拷贝和深拷贝
- 深拷贝和浅拷贝
- 深拷贝和浅拷贝
- 深拷贝和浅拷贝
- 浅拷贝和深拷贝
- 浅拷贝和深拷贝
- 深拷贝和浅拷贝
- 深拷贝和浅拷贝
- Python中的常用模块
- 题目: 一个数如果恰好等于它的因子之和,这个数被成为”完数” 例如:6=1+2+3.请编程找出1000以内的完数
- 15.odoo入门——工作遇到的odoo的一些细节和javascript实现数据库操作后跳转页面
- MySQL百万级数据量查询优化
- 读写文本文件
- c#浅拷贝/深拷贝和内存分配
- 12.IDA-虚函数和虚表
- firefox 调试接口
- 数据结构——二叉树
- 文章标题
- Python 虚拟环境 windows平台 virtualenv
- Web报表系统葡萄城报表:多级报表
- 青蛙过河 HRBUST
- JVM调优:选择合适的GC collector (一)