chenqunfeng / Blog

个人技术记录博客
6 stars 1 forks source link

垃圾回收 #7

Open chenqunfeng opened 7 years ago

chenqunfeng commented 7 years ago

Scavenge

使用了Cheney算法,是一种采用复制的方式实现的垃圾回收算法。它会将堆内存一分为二,每一部分称为semispace。这两个semispace一个属于使用中称为From空间,另一个处于闲置中称为To空间。当进行对象内存分配时,都会在From中进行。 进行垃圾回收时,会将From空间中活的对象复制到To空间中,在分代式回收的机制下,若To空间的剩余不足25%或者移动的对象曾经经历过回收,则会被复制到老生代内存空间中(老生代空间有新的算法处理,例如标记清除或者标记整理),而From空间的非活对象会被释放掉,最后将From空间和To空间进行角色互换,也就是说To空间在经历过垃圾回收之后会变为From空间,而To空间变为From空间

标记-清除

markFromRoots():
    initialise(worklist)
    for each fld in Roots
        ref <- *fld
        if ref != null && not isMarked(ref)
            setMarkded(ref)
            add(worklist, ref)
            mark()
initialise(worklist):
    worklist <- empty
mark():
    while not isEmpty(worklist)
        ref <- remove(worklist)
        for each fld in Pointers(ref)
            child <- *fld
            if child != null && not isMarked(child)
                setMarked(child)
                add(worklist, child)

markFromRoots函数 遍历根对象们,并将不为空且还未标记的对象添加标记、添加到work list中、执行mark方法。 添加到work list中的目的?主要是为了mark阶段做准备,worklist是一个用来存放和搜索需要标记对象的列表。 添加完一个对象到work list就立即执行mark方法的目的?为了最小化work list的大小,同样也可以尽可能尽快处理一个进程的垃圾回收然后进入下一个进程的垃圾回收(这里的根对象们可理解为一个个进程)。 mark函数 使用深度优先的方式遍历对象,并为活跃对象打上标记。 经过以上的处理,所有活跃对象都会被打上一个标记,任何没有打上标记的对象会在下一个阶段被当作垃圾回收。

sweep(start, end):
    scan <- start
    while scan < end
        if isMarked(scan)
            unsetMarked(scan)
        else free(scan)
        scan <- nextObject(scan)

清除阶段,会从bottom到top扫描整个heap,释放未标记的对象并重置标记对象的标记位以进入下一轮的标记清除。同时,将释放的空间块保存到nextObject中以便下次申请内存空间进行分配任务。

标记整理

因为标记清除过后可能会造成内存空间不连续而导致释放的内存空间无法被重新分配,从而提前触发了垃圾回收,显然,这种情况下的垃圾回收是没有意义的。 标记整理,是从标记清除的基础上演变而来,主要区别是,在清除掉死亡的对象之后,会将活着的对象向一端移动,移动完成之后就清理掉边界外的内存。