本文是C#高级编程的学习记录和总结。
1,为什么要有内存管理?
C#编程的优点是程序员不用担心具体的内存管理,垃圾回收器会自动处理所所有的内存清理工作。用户可以得到接近C++语言那样的效率,而不用考虑C++复杂的内存清理工作,大大提高生产力。虽不用自己关心内存清理,但也要了解回收原理,写出高效率的代码。
2,栈和堆
a,堆栈里存什么
栈存储的数据类型有:值类型,如int,float,bool等;对象的地址(其实就是值类型)
堆存啥:传说中的引用类型,string,class,interface,delegate,object
b,为什么要分为堆和栈?
区别:先进后出的数据结构,符合程序的嵌套作用域的内存分配和销毁,但这只能使用与简单的程序嵌套逻辑,对于复杂的程序嵌套逻辑栈就显得无能为力,于是就有了堆,堆能够在任何堆内地址分配大小,能够动态管理对象实例,对于复杂的引用逻辑游刃有余。
c,引用数据类型
引用数据类型的特殊之处是,在栈中存储对象的地址,在堆中分配对象实例,实际的程序中通过栈中的地址获取堆中实际的对象,只要栈中存在对象地址,那么堆中一定存在该对象的实例,知道栈中没有地址指向,最后被垃圾回收器回收。
3,垃圾回收
a,托管堆是啥?
托管堆就是垃圾回收器能管理的堆。。
b,有啥特点?
托管堆得内存分配非常类似于栈的方式,对象会在内存中一个挨一个的存放,这样就很容易使用指向下一个空闲单元的对指针,来确定下一个对象的位置。在堆上添加更多对象时也很容易调整。但这比较复杂,因为基于堆的对象的生存期和引用他们的基于栈的变量的作用域不匹配。
在垃圾回收器运行时,他会从堆中删除不再引用的所有对象,在完成删除操作后,堆会立刻把其他对象移动到堆得端部,再次形成一个连续的内存块。因此堆可以继续像栈一样确定在什么地方存储新对象。当然移动内存需要更新引用地址,这些垃圾回收器会做。
c,为啥这么分配?
速度快啊,microsoft相信,垃圾回收器做的这些压缩堆的工作会在程序运行时得到更多的性能补偿。
4,垃圾回收过程:
a,0,1,2代
0代:创建对象的时候,会把新对象放在托管对上。堆的第一部分称为0代,这里驻留了最新的对象,通常大多数比较短命的代。
1代:第一次垃圾回收之后还活着的就移动到第一代对应的部分,0代清空出来再次用来存放新对象。
2代:1代幸免于难的
b,为啥这么干?
主要就是能极大提升程序性能。通常来说最新的对象大多数都是可以立刻回收,这些对象位置相邻的话垃圾回收过程就会更快,同时相邻的对象也让程序执行更快。
c,.net还有啥优化?
大对象,85000个字节以上的,有专门自己的大对象堆,和主堆互不干扰。为啥呢?因为对象太大压缩起来浪费资源啊!所以大对象堆是不执行压缩操作的。
5,性能优化
a,第二代和大堆得回收使用后台线程执行,不会阻塞程序运行。而第0和第1代回收的时候则会阻塞程序运行,这样可以减少总暂停时间。该功能默认开启,gcconcurrent可自己配置
b,垃圾回收的平衡,专用于服务器的回收。避免由于一个线程内存过大触发回收,而其他线程不用回收的问题,减少不必要的回收。
gclatencymode配置:
batch:禁用并发设置,把垃圾回收设置为最大吞吐量
interactive:默认行为
lowlatency:保守的垃圾回收,只在系统内存存在压力是才执行完整回收。
sustainedlowlatency:只有系统存在内存压力时才进行完整的内存回收。
6,非托管资源的释放:
非托管资源,如数据库连接,io打开,文件句柄。
两种释放方法:
a,析构函数:C#中析构函数等价于Finalize方法,由于net的垃圾回收特性,垃圾回收器无法确定对象的析构函数何时执行,所以不能在析构函数中执行需要在某一时刻运行的代码,也不能寄希望于析构函数会和C++一样以特定的顺序对不同的实例调用。如果对象占用了宝贵的资源应该立即释放掉,不要等待垃圾回收器来释放了。另外析构函数会延迟对象最终从内存删除的时间。没有析构函数的对象会一次从内存中删除,如果有析构函数要两次才能从内存中,第一次没有删除对象,第二次才真正删除对象。另外运行库使用同一个线程来执行所有的对象的finalize方法。如果频繁使用析构,而且执行长时间的清理任务的话,对性能的影响就非常显著。
b,disposable接口:
系统级支持,避免了析构函数和垃圾回收器相关的问题。一般和using配合使用。用户能控制释放资源的时间。
c,析构和disposable配合使用:
配合使用:
示例如下;
public MyClass : IDisposeable
{
private bool hasDisposed = false;
public void Dispose()
{
Dispose(true)
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!hasDispose)
{
if(disposing)
{
// 释放托管资源
}
// 释放非托管资源
}
hasDispose = true;
}
~MyClass()
{
Dispose(false);
}
}
欢迎拍砖。