* 资源:在本地化中,资源用于翻译文本和图像。在这里,资源用于另一个主题:使用托管和非托管的资源——存储在托管或本机堆中的对象。
后台内存管理

* 值数据类型

* 在任何复杂的高级语言中,编译器负责把人们可以理解的变量名转化为处理器可以理解的内存地址
* 在处理器的虚拟内存中,有一个区域成为栈。栈存储不是成员对象的值数据类型
* 首先声明变量a,接着在内部代码块声明了b。然后内部代码块终止,b就超出作用域,最后a超出作用域。
*
程序第一次开始运行时,栈指针指向为栈保留的内存块末尾。栈实际上时向下填充的,即从高内存地址到低内存地址填充。当数据入栈时,栈指针就会随之调整,以始终指向下一个空闲存储单元。
*
引用数据类型

*
我们希望使用一个方法分配内存,来存储一些数据,并在该方法退出后的很长一段时间内数据仍是可用的。(例如使用new运算符来请求分配存储空间)。对于所有引用类型,此时都使用
托管堆
* 托管堆(简称堆):处理器可用内存中的另一个存储区域。
void DoWork() { Customer arabel; arabel=new Customer(); Customer
otherCustomer2=new EnhanceCustomer(); }
* Customer arabel
声明一个Customer引用arabel,在栈上给一个引用分配存储空间,但这仅仅是一个引用,而不是实际的Customer对象
* arabel=new Customer()
分配堆上的内存,一存储Customer对象(一个真正的对象,不只是地址)。然后把arabel的值设置为分配给新Customer对象的内存地址
* 总结:new方法其实就是栈+堆来储存的。栈上记录引用,堆上记录对象本身。
* 注意:与栈不同,堆的内存是向上分配的,所以空闲空间在已用空间的上方
*
垃圾回收


* 垃圾回收器运行时,他会从堆中删除不再引用的所有对象。
* 垃圾回收器释放了能释放的所有变量,就会把其他对象移动会堆的顶部,再次形成连续的内存块



注意:可以调用System.GC.Collect()方法,强迫垃圾回收器在代码的某一个地方运行。

* 创建对象时,会把这些对象放在托管堆上。堆的第一部分成为第0代。创建新对象时,会把他们移动到堆的这个部分中,因此,这里驻留了最新的对象。
* 对象会继续放在这一部分,知道垃圾回收过程第一次进行回收。这个清理过程之后仍保留的对象会被压缩,然后移动到堆的下一部分上或世代部分——第一代对应的部分。
* 此时第0代对应的部分为空,所有新的对象都再次放在这一部分。
在给对象分配内存空间时,如果超出了第0代对应的部分的容量,或者调用了CG.Collect()方法,就会进行垃圾回收。
*
在.NET中,垃圾回收提高性能的另一个领域时架构处理堆上较大对象的方式。在.NET下,较大对象有自己的托管堆,称为大托管堆(大于85000个字节的对象)。
* 为了利用包含大量内存的硬件,垃圾回收过程增加了GCSettings.LatencyMode属性
成员 说明
Batch 禁用并发设置,把垃圾回收设置为最大吞吐量。这会重写配置设置
Interactive 工作站的默认设置。它使用垃圾回收并发设置,平衡吞吐量和响应
LowLatency 保守的垃圾回收。只有在系统存在内存压力时,才能进行完整的回收。只应用于较短时间,执行特定的操作。
SustainedLowLatency 只有在系统存在内存压力时,才能进行完整的内存块回收
NoGCRegion 成功调用TryStartGCRegion后,指定不应运行的垃圾回收器,直到调用EndNoRegion为止。
*
强引用和弱引用


* 垃圾回收器不能回收仍在引用的对象的内存——这是一个强引用。它可以回收不在根表中直接或间接引用的托管内存。



如果对象相互引用,但没有在根表中引用,例如:对象A引用B,B引用C,C引用A,则GC可以销毁这些所有的对象

* 弱引用:
var myWeakPeference =new WeakReference(new DataObject()); if
(myWeakPeference.IsAlive) { DataObject strongReference =myWeakPeference.Targetas
DataObject;if(strongReference!=NULL) { //使用强引用 } else { //不可音乐 } }
*
处理非托管的资源

* 释放非托管资源(文件句柄、网络连接、数据库连接等)
* 在定义一个类时,可以使用两种机制来自动释放非托管资源
* 声明一个析构函数(或终结器),作为类的一个成员
* 在类中实现System.IDisposable接口
* 析构函数或终结器
*
C#在编译析构函数时,会隐式地把析构函数的代码编译为等价于重写Finalize()方法的代码,从而确保执行父类的Finalize()方法。下面等价于编译器为~MyClass()生成的IL:

protected override void Finalize()
{
try
{
//FInalizer implements
}
finally
{
base.Finalize();
}
}

* IDisposable接口(推荐)
* Dispose() :显示地释放由对象直接使用地所有非托管资源。

ResourceGobbler theInstance=null;
try
{
theInstance = new ResourceGobbler();
}
finally
{
theInstance.Dispose;
}

* using语句
* 下面的代码生成与try等价的IL代码

using (var theInstance = new ResourceGobbler())
{
//do your processing
}


using
语句的后面是一对圆括号,其中是引用变量的声明和实例化,该语句使变量的作用域限定在随后的语句块中。另外,在变量超出作用域时,即使出现异常,也会自动调用其Dispose()方法

* 实现IDisposable接口和析构函数
前面讨论到自定义类所使用的释放非托管资源的两种方式:

* 1.利用运行库强制执行的析构函数,但析构函数的执行时不确定的,而且由于垃圾回收器的工作方式,它会给运行库增加不可接受的系统开销
* 2.IDisposable接口提供了一种机制,该机制允许类的用户控制释放资源的时间,但需要确保调用Dispose()方法
*
如果创建了终结器,就应该实现IDisposable接口。下面是一个双重实现的例子(正确调用Dispose(),同时把实现析构函数作为一种安全机制)
using System; public class ResourceHolder : IDisposable { private bool
_isDisposed=false; public void Dispose() { Dispose(true); GC.SuppressFinalize(
this); } protected virtual void Dispose(bool disposing) { if(!_isDisposed) { if
(disposing) {//Cleanup managed objects by calling their //Dispose() Methods }
Cleanup unmanaged objects } _isDisposed=true; } ~ResourceHolder() { Dispose(
false); } public void someMethod() { //Ensure object not already disposed
before excution of any method if(_isDisposed) { throw new
ObjectDisposedException("ResourceHolder"); } //method implementation } }
* 解析:

*
1.Dispose()方法有第二个protected重载方法,它带一个布尔参数,这是真正在完成清理工作的方法。Dispode(bool)方法由析构函数和IDispose.Dispose()方法调用。
不安全的代码

*
用指针直接访问内存

* 使用指针的主要原因:向后兼容+性能
* 用unsafe关键字编写不安全的代码:(C#只允许在特别标记的代码块中使用指针)
unsafe int GetSomeNumber() { //code that can use pointers }
unsafe :可以标记在类、成员、方法中

*
指针的语法(略)

* 将指针强制转化为整数类型
* 指针类型之间的强制转换
* void指针:如果要维护一个指针,但不希望指定它指向的数据类型,就可以把指针声明为void

int *pointerToInt;
void *pointerToVoid;
pointerToVoid=(void)pointerToInt;

* 指针的算术运算:int+1代表地址+4。(智能)
* sizeof运算符:
*
结构指针:指针成员访问运算符

* 结构指针的工作方式与预定义值类型的指针的工作方式相同。但有一个条件:结构不能包含任何引用类型(因为指针不能指向任何引用类型)
struct MyStruct { public long X; public float F; } MyStruct *PMystruct; var
mystruct =new MyStruct(); PMystruct=&mystruct; (*PMystruct).X; PMystruct->Y;
*
类成员指针

*
前面说过,不能创建指向类的成员指针,这是因为垃圾回收器不维护关于指针的任何信息,只维护关于引用的信息。但是,绝大多数类都包含值类型的成员,可以为这些值类型的成员创建指针,但这需要一种特殊的语法:
使用fixed关键字。
class MyClass { public long X; public float F; } var myObject = new MyClass();
fixed(long* pX =&(myObject.X)) fixed(float* pF=&(myObject.F)) { //do something }
*
使用指针优化性能

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信