带着问题去思考!你们好函数
相对.NET 来讲。CLR去处理了,C,C++这些就须要手动去垃圾回收。性能
GC大部分容易察觉的性能问题。其实不少问题实际是哪一个都是因为对垃圾回收器的行为和预期结果理解有误。在,NET环境中,你须要更多的关注内存的性能,那么接下里咱们主要是讲内存性能问题。spa
GC实际上会调总体提升内存堆[1]的性能,由于他能高效的完成内存分配和碎片整理工做。操作系统
在Windows的本机代码模式下,内存堆维护着一张空闲内存块的列表,用于内存的分配,尽可能用低碎片化的内存堆,由于长时间运行,还要考虑内存碎片问题,内存占用率会持续增加。因此本机代码程序用大量代码实现了本身的内存分配机制,把默认的malloc函数给替换掉线程
在.NET环境中,内存分配的工做量会很小,由于内存老是整段分配的。因此不会比内存的扩大,减少和比较增长多少开销,不存在遍历空闲内存列表,几乎不会出现内存碎片,GC内存堆的效率还会更高的,由于连续分配的多个对象每每在内存堆中也是连续存放,提升就近访问的可能性。指针
在默认的内存分配流程中,有一小段代码会先检查目标对象的大小,看看内存分配缓冲区中所剩的内存够不够,若是内存分配缓冲区已耗尽,就会交由GC分配程序来检索足以容纳目标对象的空闲内存。而后一个新的分配缓冲区就会被保留下来。code
接下里看下内存分配的过程对象
class MyObject { int x; int y; int z; } static void Main(string[] args) { var x = new MyObject(); }
了解汇编语言的都知道这一流程,blog
MOV指令是数据传送指令,其余的你们能够自行去查约。大体是说,把类的方法表指针拷贝到ecx(计数暂存器)中,做为new ()的参数,调用new,把返回值(对象的地址)拷贝到寄存器中。这里你们大概了解一下就能够了队列
基本运做方式
在托管进程中存在两种内存堆(本机堆和托管堆),这里咱们说下托管堆,本机堆大你们能够自行了解下,
CLR在托管堆(Managed Heap)上为全部的.NET托管对象分配内存,也称之为GC堆,由于其中的对象都要受到垃圾回收机制的控制。
托管堆又分为两种,小对象堆和大对象堆(LOH),都拥有本身的内存段(Segment[ˈseɡmənt]).内存段的大小视配置和硬件环境而定。
小对象堆
小对象堆有什么?它又是怎么变化的?
小对象堆的内存堆分为3代,0,1,2代。第0代和第1代老是位于同一个内存段中,第2代可能跨越多个内存段,LOH也能够跨越多个内存段。包含第0代和第1代堆的内存段被称为暂时段(Ephemeral [ɪˈfemərəl] Segment ˈseɡmənt])
小对象堆中分配内存的对象生存期。若是 对象小于85000字节,CLR会把它分配在小对象堆中的第0代,一般紧挨当前已用内存空间日后分配,若是扩大内存堆时超越了内存段的边界,则就会触发垃圾回收过程。
对象老是诞生于第0代内存堆中,只要对象保持存活,每当发生垃圾回收时,GC都会把他提高一代。第0代和第1代内存堆的垃圾回收有时候被称为瞬时回收(Ephemeral Collection)
在垃圾回收的时候,可能会进行碎片整理(Compaction),也及时GC把对象物理迁移到新的位置中去,以便让内存段中的空闲空间可以连续起来使用。若是为发生碎片整理,那就只须要从新调整各块内存的边界。如下是经历几回未作碎片整理的垃圾回收以后,内存堆的分布可能以下
对象的位置没有移动,可是各代的内存堆的边界发生了变化。
若是对象到达第2代内存堆,它就会一直留在哪里直至终结。但不表明第2代内存堆只会一直变大, 若是第2代内存堆中的对象都终结了,整个内存段有没有存活[2]的对象,垃圾回收器会把整个内存段交换给操做系统,或者做为其余几代内存堆的附加段,在进行彻底垃圾回收(Full Garbge Collection)时,就会可能发生第2代内存堆的回收。
[2]:存活:GC能经过任一已知的GC跟对象(Root),沿着层层引用访问到某个对象,那么它是存活的。GC的根对象能够是程序中的静态变量,或者某个线程的堆栈被正在运行的方法占用(局部变量)或者GC句柄(好比固定对象的句柄,Pinned Handle),或是终结器队列(Finalizer Queue),有些对象可能没有受GC根对象的引用,但若是位于第2代内存堆中,那么第0代回收是不会清理这些对象的。只有彻底垃圾回收才会被清理。
若是第0代堆即将占满一个内存段,垃圾回收也没法经过碎片整理获取足够空闲内存,那么GC会分配一个新的内存段。如图:
若是第2代堆继续变大,就可能会跨越多个内存段。LOH也是。可是不管存在多少内存段,第0代和第1代老是位于同一个内存段中。之后咱们找出内存堆中有哪些对象存活时。这些会用到。
LOH
LOH,大于85000字节的对象将自动在LOH中分配内存。没有代的概念,垃圾回收期间也不会自动进行碎片化整理,可是能够人为的碎片整理。
垃圾回收的时候会形成什么影响呢?
垃圾回收是针对某一代及如下几代内存堆进行的。若是回收1代,就会回收0代。若是发生了第0代或第1代垃圾回收,程序在回收期间就会暂停运行,第二代垃圾回收,有部分回收是在后台线程运行进行的。
垃圾回收的4个阶段
在标记阶段,不须要遍历内存堆中的全部对象,只要访问那些须要回收的部分即。好比第0代回收只涉及到第0代内存堆中的对象,第1代回收将会标记第0代和第1代内存中的对象。第2代和彻底回收,须要遍历内存堆中的全部存活对象,这一开销很大。
1:垃圾回收过程的耗时几乎彻底取决于所涉及的“代”内存堆中的对象数量,而不是你分配到的对象数量,你分配1棵包含100万个对象的树,只要在下次垃圾回收以前把根对象的引用解除。就不会增长垃圾回收的耗时
2:只要已分配的内存超过某个内部阀值,就会发生这个代垃圾回收,这个阀值是持续变化的。GC会进行调整。
计数器