前言
说来真是好笑,我只是想了解值类型和引用类型,结果跳出来一大堆我本不该承受的东西。
线程
每个正在运行的程序都对应着一个进程(process)
,在一个进程内部可以有一个或多个线程(thread)
。
堆栈和堆
每个线程都拥有一块“自留地”,称为“线程堆栈”,大小为1M用于保存自身数据。
这里分为两个概念,根据 数据类型 的不同分为 堆栈 和 堆,这里的堆在.NET中叫 托管堆,其实是同一个东西,因为使用基于.NET CLR的编译器开发的代码叫托管代码,所以...
内存分配类型
两种:
- 堆栈内存
堆栈负责保持跟踪应用程序运行需要的内存
- 堆内存
对象的堆积,用于动态内存分配
public void Method1()
{
// Line 1
int i=4;
// Line 2
int y=2;
//Line 3
class1 cls1 = new class1();
}
步骤:
- 执行第一行,编译器分配一小块叫堆栈的内存。
- 执行第二行,编译器分配的内存堆叠在第一块内存的顶部。
指针总是指在最后一块内存的后面一个位置
注:内存分配和释放使用的是LIFO(Last in first out,后进先出)
逻辑。 - 执行第三行,创建对象时,它在堆栈上创建一个指针
可以理解为路径
,真实对象的内容储存在叫堆的内存中。
4.当退出这个方法时,分配到堆栈上的所有内存变量被清除,所有与int数据类型关联的变量以LIFO方式从堆栈中接触分配。
关系如图:
垃圾回收器
既然提到堆的话必须说一下这个垃圾回收器GC
,因为堆内存的分配需要通过Garbage Collector(垃圾回收器:GC)解除分配。
垃圾回收器在后台做什么呢?
为了知道内存的分配的,GC以根对象全局:应用程序(包括:静态或处于活动中的局部变量以及寄存器指向的对象)
为根目录找到下级的内存分配地址,并记录下来“绘制”对象列表根对象直接或间接引用的对象列表,其他没在列表的将被释放
,如果内存分配有更新,对象列表也会更新。
生存期垃圾回收
垃圾回收器将内存分为多个托管堆,每个代表一种生存期等级GC支持三个等级(0级、1级、2级)
。
值得一提的是,这个等级划分存在一个规则:
- 如果一个对象是新创建的,那么它的生命期可能很短。
- 如果一个对象是原来存在的,它可能会有更长的生命。
流程:当应用程序创建对象时,这些对象首先被放在0级对象列表中,当0级列表满了,GC开始释放内存资源如上所说把应用程序不引用的对象删除
。如果不能在0级删除,那么该对象被提升等级,依次类推.Net运行时支持的最大级是2级
...
那么未处理的对象越多,托管堆的大小随之增大,因此可能存在性能问题。
终结器-Finalize()
为什么对象会等级提升,我们来看看处理器的步骤:
- 新对象创建,对象被放入0级托管堆。
- 当0级列表填满时,GC运行并清理内存。
- 如果对象没有析构函数
C#编译器会把析构函数翻译(重命名)为终结器finalize()
并且不被引用,那么GC把它们清除;如果有,GC把它们放入终结队列中之后移到Freachable队列等级提升
中并在下一次迭代中执行每个对象的Finalize方法。 - 当Finalize方法执行之后被标识可回收释放掉。
那么在调用Finalize方法时,对象执行方法使对象可达,那么该对象将复活。
简单的说有析构函数的对象会在内存中存活的时间更长
.Net提供IDisposable接口
class clsMyClass : IDisposable
{
public clsMyClass()
{
}
~clsMyClass()
{
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
这里“SuppressFinalize”指示GC不要调用Finalize方法,所以不会发生GC的二次调用。
引文
- .NET中六个你必须知道的重要概念之堆栈(stack)和堆(heap)
- 深入理解.NET内存回收机制
- .net最佳实践二:使用finalize/dispose模式提升垃圾回收器性能
- 【译】.Net 垃圾回收机制原理(一)
END
- 如果文章内容能误导大家那真是再好不过了,嘻嘻嘻。
- 文章内容可能持续变更,修改或添加更多内容,以确保内容的准确性。
- 文章中大部分观点来自引文的总结,写文章的初衷是为了方便回忆。
- 更新时间:2018-09-11
网友评论