MarkSweep算法

轉載請註明:http://blog.csdn.net/HEL_WOR/article/details/50459034

MarkSweep是Hot Spot用於收集老年代的算法
在Hot Spot裏,新生代用copy算法來收集,cheney算法是copy算法的一種,老年代用MarkSweep算法收集垃圾,這兩種算法都屬於跟蹤收集器,即通過目標對象是否可達來判斷是否是需要收集的垃圾。

關於這兩種算法的大致描述,在 JVM的垃圾回收有描述。

對於MarSweep的大致實現原理和代碼,在Baby’s First Garbage Collector已經有很詳細的描述了。

不過到底自己看資料吸收了多少,只有動手實現一次才能知道,所以就有了這篇博客作爲記錄。
因爲在Baby’s First Garbage Collector作者已經用C語言實現了一次,因爲不想寫着寫着就和他寫的代碼是一樣的了,所以我是C#實現了一次,但不管用C#還是用Java實現都是有問題的,因爲我沒辦法自己控制內存的分配和銷燬,不過我的目的是爲了理清算法的邏輯,如果有需要再換種語言來寫吧。

MarkSweep算法的主要有兩個步驟,第一步是標記(Mark),第二步是整理(Sweep)。而實現也只需要兩個結構,一個是棧,以用來模擬虛擬機棧,進入棧中的對象都是活躍的(或者說可達的)對象,另一個是一條鏈表,這條鏈表上記錄所有被已被創建的對象。
我們需要一個標誌來表示某個對象是否是可達的,可以通過在定義對象時設置一個標誌位,也可以用位圖來完成。
當完成標記(Mark)過程,進入整理(Sweep)邏輯,我們只需要遍歷之前定義的那條鏈表,釋放掉鏈表中未被標記可達的對象即完成垃圾回收了。整個MarkSweep算法的邏輯就是如此。

MarkSweep類代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkSweep
{
    public class MarkSweep
    {
        /// <summary>
        /// GC前創建對象數
        /// </summary>
        public int totalNmuBeforeGc;

        /// <summary>
        /// 設置已被掃描
        /// </summary>
        /// <param name="model">對象</param>
        private void Mark(Model model) 
        {
            if (model == null || model.marked) 
            {
                return;
            }

            model.marked = true;
            Mark(model.next);
        }

        /// <summary>
        /// 對棧中對象設置已被掃描
        /// </summary>
        /// <param name="stack">模擬的虛擬機棧</param>
        private void MarkAll(VMStack vm) 
        {
            for (int i = 0; i < vm.Index; i++) 
            {
                this.Mark(vm.stack[i]);
            }
        }

        /// <summary>
        /// 整理
        /// </summary>
        /// <param name="vm">模擬的虛擬機棧</param>
        private void Sweep() 
        {
            //// head對此線程應是全局唯一的 對其他線程而言不是 因爲VMStack不是static的
            Model head = VMStack.Head;
            Model entry = head.next;
            Model forward = head;

            //// 開始遍歷所有已創建對象
            while (entry != null) 
            {
                //// 如果沒有被掃描標記 說明此對象已經不可達 釋放掉
                if (!entry.marked)
                {
                    //// 處理指針
                    forward.next = entry.next;
                    entry.next = null;

                    //// 在這裏完成free操作
                    //// free(entry)
                    entry = forward.next;
                    Model.createdModelNum--;
                }
                else 
                {
                    //// 更新指針
                    entry = entry.next;
                    forward = forward.next;
                }
            }
        }

        /// <summary>
        /// GC
        /// </summary>
        /// <param name="vm">模擬的虛擬機棧</param>
        public void GC(VMStack vm) 
        {
            this.totalNmuBeforeGc = Model.createdModelNum;
            this.MarkAll(vm);
            this.Sweep();
        }
    }
}

定義模擬虛擬機棧:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkSweep
{
    public class VMStack
    {
        /// <summary>
        /// 棧最大深度
        /// </summary>
        public const int stackMaxDepth = 1024;

        /// <summary>
        /// 定義棧
        /// </summary>
        public Model[] stack = new Model[stackMaxDepth];

        /// <summary>
        /// 已創建對象鏈表尾指針
        /// </summary>
        public static Model Tail = new Model();

        /// <summary>
        /// 已創建對象鏈表頭指針,當尾指針後移時,頭指針始終指向和尾指針第一次指向的對象.
        /// </summary>
        public static Model Head = Tail;

        /// <summary>
        /// 定義索引
        /// </summary>
        private static int index = 0;

        /// <summary>
        /// 封裝
        /// </summary>
        public int Index 
        {
            get { return index; }
            private set { index = value; }
        }

        /// <summary>
        /// 出棧
        /// </summary>
        /// <returns></returns>
        public object Pop() 
        {
            if (index == 0) 
            {
                throw new Exception("stack under flow");
            }

            return this.stack[index--];
        }

        /// <summary>
        /// 入棧
        /// </summary>
        /// <param name="model">待入棧對象</param>
        public void Push(Model model) 
        {
            if(index == stackMaxDepth - 1)
            {
                throw new Exception("stack over flow");
            }

            model.marked = true;
            this.stack[index] = model;
            index++;
        }
    }
}

定義模擬對象:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkSweep
{
    /// <summary>
    /// 假設這個對象是通用對象
    /// </summary>
    public class Model
    {
        /// <summary>
        ///
        /// </summary>
        public int intValue;

        /// <summary>
        /// 維護一條所有已創建對象鏈表
        /// </summary>
        public Model next;

        /// <summary>
        /// 是否已被引用
        /// </summary>
        public bool marked;

        /// <summary>
        /// 已創建對象數量
        /// </summary>
        public static int createdModelNum = 0;

        /// <summary>
        /// 構造函數 並維護到已創建對象鏈表
        /// </summary>
        public Model() 
        {
            this.intValue = 0;
            this.marked = false;
            this.next = null;

            //// 頭結點作爲標誌位不含值 先爲頭結點初始化 實例化後再做指針操作
            if (VMStack.Tail != null) 
            {
                VMStack.Tail.next = this;
                VMStack.Tail = this;
                createdModelNum++;
            }
        }
    }
}

這樣即可完成調用:

MarkSweep ms = new MarkSweep();
            ms.GC(stack);
            Console.WriteLine(string.Format("total model num: {0}, after gc, remain model num: {1}", ms.totalNmuBeforeGc, Model.createdModelNum));
發佈了31 篇原創文章 · 獲贊 11 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章