垃圾回收GC算法

背景

动态创建的所有对象(在C ++和Java中使用new)都在堆中分配了内存。如果继续创建对象,则可能会出现“内存不足”错误,因为无法将堆内存分配给对象。因此,我们需要通过释放所有程序不再引用的对象(或不可达对象)的内存来清除堆内存,以便为后续的新对象提供空间。该内存可以由程序员自己释放,但对于程序员来说似乎是一个开销,在这里垃圾回收很容易解决,它会自动释放所有未引用对象的堆内存。
有许多GC算法在后台运行。其中之一是标记和清除。

标记和清除算法
任何垃圾收集算法都必须执行2个基本操作。首先,它应该能够检测所有无法访问的对象,其次,它必须回收垃圾对象使用的堆空间,并使该空间可再次用于程序。
以上操作由标记和扫描算法分两个阶段执行:
1)标记阶段
2)扫描阶段

 

标记阶段
创建对象时,其标记位设置为0(false)。在标记阶段,我们将所有可访问对象(或用户可以引用的对象)的标记位设置为1(true)。现在要执行此操作,我们只需要进行图遍历,DFS深度优先搜索算法将对我们有用。在这里,我们可以将每个对象视为一个节点,然后访问该节点(对象)可到达的所有节点(对象),并一直进行到我们访问了所有可到达节点为止。

  • 根是引用对象的变量,并且可以通过局部变量直接访问。我们将假设我们只有一个根。
  • 我们可以通过以下方式访问对象的标记位:markedBit(obj)。

算法-标记阶段:

Mark(root)
    If markedBit(root) = false then
        markedBit(root) = true
        For each v referenced by root
             Mark(v)

注意:如果我们有多个根,则只需为所有根变量调用Mark()。

 

扫描阶段
顾名思义,它“清除”了无法访问的对象,即清除了所有无法访问的对象的堆内存。标记值设置为false的所有那些对象将从堆内存中清除,对于所有其他对象(可访问对象),将标记位设置为true。
现在,所有可及对象的标记值都设置为false,因为我们将运行算法(如果需要),然后再次进入标记阶段以标记所有可及对象。

算法–扫描阶段

Sweep()
For each object p in heap
    If markedBit(p) = true then
        markedBit(p) = false
    else
        heap.release(p)

标记清除算法称为跟踪垃圾收集器,因为它可以跟踪程序直接或间接访问的对象的整个集合。

例:

a)所有对象的标记位都设置为false。

b)可达对象标记为true

c)从堆中清除不可访问的对象。

标记和扫描算法的优点

  • 它使用循环引用来处理情况,即使在循环的情况下,该算法也永远不会陷入无限循环。
  • 在算法执行期间不会产生额外的开销。

标记和扫描算法的缺点

  • 标记清除方法的主要缺点是,在运行垃圾回收算法时,正常程序的执行被暂停。
  • 另一个缺点是,在程序上执行“多次扫描”算法后,可到达的对象最终被许多小的未使用的内存区域分隔开。请看下图,以更好地理解。
    数字:

在此,白色块表示可用内存,而灰色块表示所有可到达对象占用的内存。
现在,自由段(用白色表示)的大小各不相同,假设5个自由段的大小分别为1、1、2、3、5(单位为大小)。
现在,我们需要创建一个占用10个单位内存的对象,现在假定只能以连续的块形式分配内存,尽管我们有12个单位的可用内存空间,但无法创建对象内存不足错误。这个问题被称为“碎片”。我们在“碎片”中有可用的内存,但是我们无法利用该内存空间。
我们可以通过压缩来减少碎片;我们将内存内容混洗以将所有可用内存块放在一起,形成一个大块。现在考虑上面的示例,压缩后,我们有一个连续的大小为12个单位的空闲内存块,因此现在我们可以将内存分配给大小为10个单位的对象。

参考文献:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值