垃圾回收算法

来源:互联网 发布:mysql可视化建立外键 编辑:程序博客网 时间:2024/06/06 01:31
1、传统的C/C++编程语言,需要程序员负责回收已经分配的内存,显示进行垃圾回收是一件比较困难的事情,因为程序员不是总是知道内存应该何时被释放。这里面就涉及到内存泄漏。什么是内存泄漏?就是如果一些分配出去的内存得不到及时的回收,就会引起系统运行速度的下降,甚至导致程序的瘫痪,这种现象被称为内存泄漏。Java语言不需要程序员直接控制内存回收。通常JRE会提供一个后台线程来进行检测和控制,一般都是在CPU空闲或内存不足时自动进行垃圾回收,回收那些不再使用的内存。2、Java的堆内存是一个运行时数据区,用以保存类的实例(对象)。JVM的堆内存中存储着正在运行的应用程序所建立的所有对象。3.垃圾回收一种动态存储管理技术。按照特定的垃圾回收算法实现内存资源的自动回收功能。下面有几种经典的垃圾回收算法,这些算法尽管出现于60、70年代,但是现在的CLR、JVM等上面的垃圾回收器,仍然使用了它们。

引用计数算法

引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1;当删除一个指向自己的指针时,计数值减1,如果计数值减为 0,说明已经不存在指向该对象的指针了,所以它可以被安全的销毁了。引用计数算法的优点在于内存管理的开销分布于整个应用程序运行期间,非常的“平滑”,无需挂起应用程序的运行来做垃圾回收;而它的另外一个优势在于空间上的引用局部性比较好,当某个对象的引用计数值变为0时,系统无需访问位于堆中其他页面的单元,而后面我们将要看到的几种垃圾回收算法在回收前都回遍历所有的存活单元,这可能会引起换页(Paging)操作;最后引用计数算法提供了一种类似于栈分配的方式,废弃即回收,后面我们将要看到的几种垃圾回收算法在对象废弃后,都会存活一段时间,才会被回收。引用计数算法有着诸多的优点,但它的缺点也是很明显的。首先能看到的一点是时间上的开销,每次在对象创建或者释放时,都要计算引用计数值,这会引起一些额外的开销;第二是空间上的开销,由于每个对象要保持自己被引用的数量,必须付出额外的空间来存放引用计数值;引用计数算法最大的缺点就在于它无法处理环形引用。

标记-清除算法

标记-清除(Mark-Sweep)算法依赖于对所有存活对象进行一次全局遍历来确定哪些对象可以回收,遍历的过程从根出发,找到所有可达对象,除此之外,其它不可达的对象就是垃圾对象,可被回收。整个过程分为两个阶段:标记阶段找到所有存活对象;清除阶段清除所有垃圾对象。相比较引用计数算法,标记-清除算法可以非常自然的处理环形引用问题,另外在创建对象和销毁对象时时少了操作引用计数值的开销。它的缺点在于标记- 清除算法是一种“停止-启动”算法,在垃圾回收器运行过程中,应用程序必须暂时停止,所以对于标记-清除算法的研究如何减少它的停顿时间,而分代式垃圾收集器就是为了减少它的停顿时间,后面会说到。另外,标记-清除算法在标记阶段需要遍历所有的存活对象,会造成一定的开销,在清除阶段,清除垃圾对象后会造成大量的内存碎片。

标记-缩并算法

标记-缩并算法是为了解决内存碎片问题而产生的一种算法。 它的整个过程可以描述为:标记所有的存活对象;通过重新调整存活对象位置来缩并对象图;更新指向被移动了位置的对象的指针。标记-压缩算法最大的难点在于如何选择所使用的压缩算法,如果压缩算法选择不好,将会导致极大的程序性能问题,如导致Cache命中率低等。一般来说,根据压缩后对象的位置不同,压缩算法可以分为以下三种:1. 任意:移动对象时不考虑它们原来的次序,也不考虑它们之间是否有互相引用的关系。 2. 线性:尽可能的将原来的对象和它所指向的对象放在相邻位置上,这样可以达到更好的空间局部性。 3. 滑动:将对象“滑动”到堆的一端,把存活对象之间的自由单元“挤出去”,从而维持了分配时的原始次序。

节点拷贝算法

节点拷贝算法是把整个堆分成两个半区(From,To), GC的过程其实就是把存活对象从一个半区From拷贝到另外一个半区To的过程,而在下一次回收时,两个半区再互换角色。在移动结束后,再更新对象的指针引用,节点拷贝算法由于在拷贝过程中,就可以进行内存整理,所以不会再有内存碎片的问题,同时也不需要再专门做一次内存压缩。,而它最大的缺点在于需要双倍的空间。


引用的文章:http://blog.csdn.net/yclzh0522/article/details/6982442





0 0
原创粉丝点击