C#垃圾回收器的 内存循环周期回收周期是多长

值  类 型: 所有的值类型都集成自 嘚GC机制有这样两个问题:
  首先GC并不是能释放所有的资源。它不能自动释放非托管资源

  第二,GC并不是实时性的这将会造成系統性能上的瓶颈和不确定性。  GC并不是实时性的这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口IDisposable接口定义了Dispose方法,这个方法鼡来供程序员显式调用以释放非托管资源使用using语句可以简化资源管理。  


  2、托管资源和非托管资源

上面介绍到GC只释放托管资源,那么什么是托管资源和费托管资源

  托管资源  托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存循环周期資源托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收

  非托管资源非托管资源指的是.NET不知道洳何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象例如文件,窗口网络连接,数据库连接画刷,图标 等这类資源,

垃圾回收器在清理的时候会调用Object.Finalize()方法默认情况下,方法是空的对于非托管对象,需要在此方法中编写回收非托管资源的代码鉯便垃圾回收器正确回收资源。

总结:托管资源是释放由GC来完成释放的时间吧不一定,一般是系统感觉内存循环周期吃紧会进行紧急囙收资源。一个对象想成为被回收首先需要成为垃圾,GC是通过判断对象及其子对象有没有指向有效的引用

如果没有GC就认为它是垃圾。垃圾回收机制通过一定的算法得到哪些没有被被引用、或者不再调用的资源当这些垃圾达到一定的数量时,回启动垃圾回收机制GC回收實际上是调用了析构函数。

垃圾回收机制意味着你不需要担心处理不再需要的对象了咱们关心的主要是非托管资源的释放。

垃圾回收时對象一共有三代 :01,2每一代都有自己的内存循环周期预算,空间不足的时候会调用垃圾回收为了提高性能都是按代回收,第0代超预算之后就回收第0代的对象而存活下来的对象就提升为第1代,

依次类推而往往经过多次0代的垃圾回收才能回收一次第1代。

GC进行垃圾回收昰系统决定的下面是进行强制回收的执行代码(非特殊情况下不要使用此方法,会影响系统效率削弱垃圾回收器中优化引擎的作用,洏垃圾回收器可以确定运行垃圾回收的最佳时间

//对所有代进行垃圾回收
//对指定的代进行垃圾回收。
 

  3、非托管资源的释放

在定义一個类时可以使用两种不同的机制类释放非托管资源,这两周机制有时候通常放在一起使用

1、声明析构函数(终结器)吗作为类的成员

  构造函数可以在创建对象实例的时候执行某些操作,析构函数正好相反是资源创建以后被系统回收的时候执行的操作垃圾回收器在囙收对象之前会调用析构函数,所以在函数代码块中可以写释放非

托管资源的代码析构函数没有返回值,没有参数没有修饰符

析构函数会被编辑器翻译成下面的代码:

最终析构函数会被翻译成上面的代码块重写基类的Finalize()方法,然后最终调用 Base.Finalize()方法

注意!大量的使用析構函数会影响效率!带有析构函数的对象会被系统执行两次才会被释放掉。GC执行释放资源时没有析构函数的资源会被直接释放掉,假如目标对象有析构函数会被先放进一个叫做“终结队列”的

项中去,然后系统调用另一个高优先级线程来执行 Finalize()方法GC继续回收其它对象。等方法执行完以后会将对象从终结队列中清除出去此时对象才是真正意义上的垃圾。等GC执行资源回收的时候才回释放掉终结队列里面嘚对象。

  • 托管堆中内存循环周期的释放和析构函数的执行分别属于两个不同的线程

  • 带有析构函数的对象其生命周期会变长,由上知会进荇两次垃圾回收处理才能被释放如此一来将导致程序性能的下降。

  • 若一个对象引用了其他对象时当此对象不能够被释放时,则其引用對象也就无法进行内存循环周期的释放也就意味着带有析构函数的对象和其引用对象将从第0代提升到第一代,毫无疑问将影响程序的性能

综上所述,建议是不要实现其析构函数这将大大降低程序的性能。

② 如果我们不调用 Diapose()方法系统会调用使用终结器操作,最后吔是释放非托管资源

从例子可以看出,对于手动回收(disposing为true)除了非托管资源,还可以通知其他托管对象Dispose()因为这时候内部的托管对象肯定沒回收。而到了自动回收就不能通知其他托管对象了,因为垃圾回收可能已经把他们回收了

而且垃圾回收会自动回收他们,也不用你通知了

当释放非托管资源时我们应该显式的去实现Dipose()方法或者Close()方法,但是万一我们忘记显式去调用方法此时还有一条退路,CLR会自动调用Finalize()方法

很显然调用Finalize()方法会大大降低程序的性能,没关系上述释放模式关键的一点是通过手动释放调用Dispose()方法可以阻止Finalize()方法的调用,换言之上述通过手动释放既释放了非托管资源又加快了程序运行的速度,毫无疑问这是一种完美的解决方案。

1、Finalize是系统决定执行的我们无法干涉。Dispose是可以我们调用来释放的

2、Finalize只能释放费托管资源,Dispose既可以释放托管资源也可以释放非托管资源

开发过程中遇到的内存循环周期泄露情况如何解决的?

内存循环周期泄露是指一块被分配的内存循环周期既不能使用又不能回收,直到浏览器进程结束C#和Java等语言采鼡了自动垃圾回收方法管理内存循环周期,几乎不会发生内存循环周期泄露我们知道,浏览器中也是采用自动垃圾回收方法管理内存循環周期但由于浏览器垃圾回收方法有bug,会产生内存循环周期泄露

2、内存循环周期泄露的几种情况:

(1)、当页面中元素被移除或替换时,若え素绑定的事件仍没被移除在IE中不会作出恰当处理,此时要先手工移除事件不然会存在内存循环周期泄露。

(2)、由于是函数内定义函数并且内部函数--事件回调的引用外暴了,形成了闭包闭包可以维持函数内局部变量,使其得不到释放

1、定义和用法:垃圾回收机制(GC:Garbage Collection),执荇环境负责管理代码执行过程中使用的内存循环周期。

2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量然后释放其內存循环周期。但是这个过程不是实时的因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行

fn1中定义的obj为局部变量,而当调用结束后出了fn1的环境,那么该块内存循环周期会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中返回的对象被全局变量b所指向,所以该块内存循环周期并不会被释放

4、垃圾回收策略:标记清除(较为常用)和引用计数。

  定义和用法:当变量进入环境时将变量标记"进入环境",当变量离开环境时标记为:"离开环境"。某一个时刻垃圾回收器会过滤掉环境中的变量,以及被环境变量引用嘚变量剩下的就是被视为准备回收的变量。

  到目前为止IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不過垃圾收集的时间间隔互不相同

  定义和用法:引用计数是跟踪记录每个值被引用的次数。

  基本原理:就是变量的引用次数被引用一次则加1,当这个引用计数为0时被视为准备回收的对象。

1、什么时候触发垃圾回收

垃圾回收器周期性运行,如果分配的内存循环周期非常多那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题

IE6的垃圾回收是根据内存循环周期分配量运荇的,当环境中的变量对象,字符串达到一定数量时触发垃圾回收垃圾回收器一直处于工作状态,严重影响浏览器性能

IE7中,垃圾回收器会根据内存循环周期分配量与程序占用内存循环周期的比例进行动态调整开始回收工作。

2、合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象

3、GC缺陷:(1)、停止响应其他操作;

在mdn上看到的内存循环周期管理

使用分配到的内存循环周期(读、写)

不需要时將其释放\归还

在js里面当你变量初始化的时候就已经在在为变量分配内存循环周期了

有些函数调用结果是分配对象内存循环周期

有些方法分配新变量或者新对象: 理解为当使用函数,或是一些方法的话就会为其变量分配内存循环周期

这是最天真的垃圾收集算法。此算法把“對象是否不再需要”简化定义为“对象有没有其他对象引用到它”如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收

該算法有个限制:无法处理循环引用。在下面的例子中两个对象被创建,并互相引用形成了一个循环。它们被调用之后会离开函数作鼡域所以它们已经没有用了,可以被回收了然而,引用计数算法考虑到它们互相都有至少一次引用所以它们不会被回收。

这个算法紦“对象是否不再需要”简化定义为“对象是否可以获得”

这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)垃圾回收器将定期从根开始,找所有从根开始引用的对象然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象

这个算法比前一个要好,因为“有零引用的对象”总是不可获得的但是相反却不一定,参考“循环引用”

從2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法所有对JavaScript垃圾回收算法的改进都是基于标记-清除算法的改进,并没有改进标记-清除算法本身和它对“对象是否不再需要”的简化定义

JS的垃圾回收机制了解吗?

JS中最常见嘚垃圾回收方式是标记清除

工作原理:是当变量进入环境时,将这个变量标记为“进入环境”当变量离开环境时,则将其标记为“离開环境”标记“离开环境”的就回收内存循环周期。

1.    垃圾回收器在运行的时候会给存储在内存循环周期中的所有变量都加上标记。

4.    垃圾回收器完成内存循环周期清除工作销毁那些带标记的值并回收他们所占用的内存循环周期空间。

工作原理:跟踪记录每个值被引用的佽数

1.    声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1

3.    当包含这个引用类型值的变量又被赋值荿另一个值了,那么这个引用类型值的引用次数减1.

5.    当垃圾收集器下一次运行时它就会释放引用次数是0的值所占的内存循环周期。

但是循環引用的时候就会释放不掉内存循环周期循环引用就是对象A中包含另一个指向对象B的指针,B中也包含一个指向A的引用

因为IE中的BOM、DOM的实現使用了COM,而COM对象使用的垃圾收集机制是引用计数策略所以会存在循环引用的问题。

解决:手工断开js对象和DOM之间的链接赋值为null。IE9把DOM和BOM轉换成真正的JS对象了所以避免了这个问题。

什么情况会引起内存循环周期泄漏

虽然有垃圾回收机制但是我们编写代码操作不当还是会慥成内存循环周期泄漏。

原因:全局变量不会被回收。

解决:使用严格模式避免

原因:闭包可以维持函数内局部变量,使其得不到释放

解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中删除对dom的引用。

原因:虽然别的地方删除了泹是对象中还存在对dom的引用

原因:定时器中有dom的引用,即使dom删除了但是定时器还在,所以内存循环周期中还是有这个dom

解决:手动删除萣时器和dom。

原因:div中的ul li  得到这个div会间接引用某个得到的li,那么此时因为div间接引用li即使li被清空,也还是在内存循环周期中并且只要li不被删除,他的父元素都不会被删除

什么放在内存循环周期中?什么不放在内存循环周期中

基本类型的值存在内存循环周期中,被保存茬内存循环周期中从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本

引用类型的值是对象,保存在内存循环周期中

1.    包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针从一个变量向另一个变量复制引用类型的值,复制的其实是指针因此两个变量最终都指向同一个对象。

2.    js不允许直接访问内存循环周期中的位置也就是不能直接访问操作对象的内存循环周期空间。在操作对象时实际上是在操作对象的引用而不是实际的对象。

  一、堆栈空间分配区别:
  1、栈():由自动分配释放 存放函数的参数值,局部变量的值等其操作方式类似于数据结构中的栈;
  2、堆(): 一般由程序员分配释放,若程序员不釋放程序结束时可能由OS回收,分配方式倒是类似于链表
  二、堆栈缓存方式区别:
  1、栈使用的是, 他们通常都是被调用时处于存储空间中调用完毕立即释放;
  2、堆是存放在二级缓存中,生命周期由虚拟机的算法来决定(并不是一旦成为孤儿对象就能被回收)所以调用这些对象的速度要相对来得低一些。
  三、堆栈数据结构区别:
  堆(数据结构):堆可以被看成是一棵树如:堆排序;
  栈(数据结构):一种先进后出的数据结构。


我要回帖

更多关于 内存循环周期 的文章

 

随机推荐