C#内存管理
一、变量类型
C#的变量类型分为值类型,引用类型、指针类型和指令类型。所有的值类型都继承于System.ValueType,在C#中的值类型包括bool、byte、char、decimal、double、enum、float、int、long、sbyte、short、struct、uint、ulong、ushort等。在引用类型均继承自System.Object,除了Object其自身,引用类型包括class、interface、delegate、objecthe string。 一般通常了解值类型和引用类型,其中引用类型总是在堆上创建,值类型和指针类型总是在它声明的地方创建。
二、程序执行过程
public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}
在程序执行过程中,在栈中为pValue、result分配内存,在方法作用域结束后将会在栈中销毁内存,如下图所示。public class MyInt
{
public int MyValue;
}
执行如下:
public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}
在程序执行中,会在堆中为MyInt分配一块内存空间,同时在栈中为pValue分配空间,然后为result在栈中分配内存,此时result中存储的是MyInt在堆中的地址,方法执行完后,在栈中的result和pValue将会销毁,但MyInt将会在堆中,在GC回收时销毁。当我们达到一定内存瓶颈时我们需要堆中要有更多的空间,这时GC出场。GC将停止所有运行中的线程(完全停止),找出在堆中所有没有被引用的对象并且删除它们。GC将重新组织所有在堆中的对象以获得空间,调整所有在堆以及栈中的指针。就像你想象的那样,这将花费十分昂贵的性能,所以现在你就能看出当你在写高性能代码时,关注堆栈中有什么是如此的重要。
注:1.GC回收一般发生在程序内存不够用时,否则不会发生除非手动调用。2.手动调用GC可实现强制“尝试”回收资源。3.GC中的所有资源是分“代”的,每次检测堆中的对象是否还有引用,如果有当前的“代”数加一,否则减一,GC回收“代”数最小的资源,这也就解释了为什么即使我手动调用GC.Collect()方法之后,对象还是没有马上被回收的问题。4.频繁调用GC.Collect()会导致频繁的线程中断,从而严重影响性能。
三、参数内存
当我们调用方法时,如下事情将发生:当我们执行一个方法时需要在栈上创建一个空间。这包含了一个GOTO指令的地址调用(指针),所以当线程执行完我们的方法后它知道如何返回并继续执行程序。
在栈中的参数处理分为值类型和引用类型,值类型的参数将会复制拷贝,引用类型将会拷贝引用地址。因此,如果我们有一个很大的值类型(例如很大的一个结构体)并且将它作为参数传递至方法时,每次它将被拷贝复制并且花费很大的内存和CPU时间。栈的空间是有限的,正如从水龙头往杯里灌水一样,它总会溢出的。结构体是值类型,可能会非常大,我们在使用时必须要注意。当我们在传递内存比较大的参数时,为了避免栈内存的空间浪费,可以传递指向值得引用,eg:void DoSomething(ref struct s); ref的作用是用来传递指向值得引用。此时当参数值改变时,相应的被传变量的值也会改变,参数在栈中将会保存一个指向原变量地址的地址。
总结:
1. 值类型当参数时,复制拷贝为一个栈上的新对象,使用后回收。
2. 值类型当参数时,会发生拷贝现象,所以对一些“很大”的结构体类型会产生很严重的效率问题,可尝试用ref 关键字将结构体包装成引用类型进行传递,节省空间及时间。
3. 引用类型传递的是引用地址,即多个事物指向同一个内存块,如果更改内存中的值将同时反馈到所有其引用的对象上。
4. Ref关键字传递的是引用类型的指针,而非引用类型地址。
四、深拷贝VS浅拷贝
当我们对于一个引用类型赋值时,都是讲引用类型的指针进行拷贝,当一个发生改变时另一个也会改变。但我们通常需要进行深度赋值,此时一个发生改变时,另一个不会改变。
下面我们将实现这个接口:
public class Shoe : ICloneable
{
public string Color;
#region ICloneable Members
public object Clone()
{
Shoe newShoe = new Shoe();
newShoe.Color = Color.Clone() as string;
return newShoe;
}
#endregion
}
public Dude CopyDude()
{
Dude newPerson = new Dude();
newPerson.Name = Name;
newPerson.LeftShoe = LeftShoe.Clone() as Shoe;
newPerson.RightShoe = RightShoe.Clone() as Shoe;
return newPerson;
}
上一篇: CAD打印图纸怎么去掉图纸图框的白边?
下一篇: react学习记录-事件监听