zoukankan      html  css  js  c++  java
  • 蛙蛙推荐:.net中的游标链表和普通链表对GC的影响

    摘要:
    对普通链表进行添加和删除操作,会创建和销毁对象,如果操作太频繁会对GC造成压力,而游标链表是事先分配好一个大数组,然后用数组的下标代替普通链表的引用指针,这样链表节点的添加删除,只是下标指向的改变,不会创建和销毁对象,相当于自己管理了内存,所以降低了GC的压力。
    性能测试模型:
    1、往链表里添加500w个int节点
    2、把这500w个节点删除
    3、重复1和2进行10次,分别记录各代gc回收次数,gc堆大小及执行时间。
    性能测试结果
    游标链表
    err:0
    gen:24,gen:15,gen:5
    totalMemory:160217492
    tack time:19358
    .NET自带普通链表
    gen:213,gen:125,gen:21
    totalMemory:120221380
    tack time:18024
    性能测试结论:
    对游标链表的频繁添加、删除操作引起的GC回收次数明显比普通链表要少的多,但游标链表因为使用了额外的数组记录空闲节点列表,所以占用内存大一些,由于每个标准操作的子步骤数比普通链表多一些,所以总体销号时间也稍大于普通链表,但不明显。
    单元测试用例:
    操作:
    1、往链表的头上依次添加节点1,2,3加上默认的0节点共4个节点。
    2、从链表的尾部连续删除两个节点
    3、从链表的尾部开始,向前遍历节点,并打印节点数据
    预期
    输出数据2,3
    单元测试结果:
    通过
    测试部分代码
    class Program {
        
    static void Main(string[] args) {
            
    //UnitTest();

            
    const int max = 500*10000;
            Stopwatch watch 
    = Stopwatch.StartNew();
            
    //TestLinkdList(max, 10); //这一句和下一句要分别测试,别同时测
            TestCursorList(max, 10);

            Console.WriteLine(
    "gen:{0},gen:{1},gen:{2}",
                GC.CollectionCount(
    0),GC.CollectionCount(1),GC.CollectionCount(2));
            Console.WriteLine(
    "totalMemory:{0}",GC.GetTotalMemory(false));
            Console.WriteLine(
    "tack time:{0}",watch.ElapsedMilliseconds);
            Console.ReadKey();
        }

        
    private static void UnitTest() {
            CursorList
    <int> list = new CursorList<int>(3);
            list.AddHeader(
    1);
            list.AddHeader(
    2);
            list.AddHeader(
    3);
            list.RemoveTail();
            list.RemoveTail();
            CursorListNode
    <int> node = list.Tail;
            
    while (node != null//预期输出2,3
            {
                Console.WriteLine(node.Data);
                node 
    = node.Next;
            }
        }

        
    private static void TestCursorList(int max, int iteration)
        {
            CursorList
    <int> list = new CursorList<int>(max);
            
    int err = 0;
            
    for (int k = 0; k < iteration; k++) {
                
    for (int i = 0; i < max; i++)
                    
    if (list.AddHeader(i) == null) err++;
                
    for (int i = 0; i < max; i++)
                    list.RemoveTail();
            }
            Console.WriteLine(
    "err:{0}", err);
        }
        
    private static void TestLinkdList(int max, int iteration) {
            LinkedList
    <int> list = new LinkedList<int>();
            
            
    for (int k = 0; k < iteration; k++) {
                
    for (int i = 0; i < max; i++)
                    list.AddFirst(i);
                
    for (int i = 0; i < max; i++)
                    list.RemoveLast();
            }
        }
    }

    游标链表实现代码
    为了简单起见,只是先了在头部添加和移除尾部节点的方法。
    public class CursorListNode<T> {
        
    public CursorListNode<T> Next { getset; }
        
    public CursorListNode<T> Prior { getset; }
        
    internal int Index { getset; }
        
    public T Data { getset; }
    }
    public class CursorList<T> {
        
    private readonly Queue<int> _freeQ = null;
        
    private readonly CursorListNode<T>[] _list = null;

        
    public CursorList(int capacity) {
            _freeQ 
    = new Queue<int>(capacity+1);
            _list 
    = new CursorListNode<T>[capacity+1];
            
            _list[
    0= Header = Tail = new CursorListNode<T> {
                Index 
    = 0,
                Data 
    = default(T),
                Next 
    = null,
                Prior 
    = null
            };

            
    for (int i = 1; i < capacity+1; i++)
            {
                _freeQ.Enqueue(i);
                _list[i] 
    = new CursorListNode<T> {
                    Index 
    = -1,
                    Data 
    = default(T),
                    Next 
    = null,
                    Prior 
    = null
                };
            }
        }
        
    public CursorListNode<T> AddHeader(T data) {
            
    if(_freeQ.Count < 1return null;
            
    int newIndex = _freeQ.Dequeue();

            CursorListNode
    <T> newNode = _list[newIndex];
            newNode.Index 
    = newIndex;
            newNode.Data 
    = data;
            newNode.Next 
    = null;
            newNode.Prior 
    = Header;

            Header.Next 
    = newNode;
            Header 
    = newNode;

            
    return newNode;
        }

        
    public void RemoveTail() {
            
    if(Tail == nullreturn;
            _freeQ.Enqueue(Tail.Index);
            
    if (Tail.Next != null)
            {
                Tail 
    = _list[Tail.Next.Index];
                Tail.Prior 
    = null;
            }
            
    else
                Tail 
    = null;
            
        }

        
    public CursorListNode<T> Header { getset; }
        
    public CursorListNode<T> Tail { getset; }
    }

    参考链接:
    CursorList.cpp - Implementation for cursor linked list
    http://www.cplusplus.happycodings.com/Data-Structures-and-Algorithm-Analysis-in-C++/code33.html
    链表的游标法实现 cursor_list
    http://blog.csdn.net/liuzongqiang/archive/2008/01/06/2027762.aspx
  • 相关阅读:
    【论文阅读笔记】《StarGAN》
    【数据分析入门】泰坦尼克号生存率预测(一)
    【DLPytorch】Optimizer(一)
    【论文阅读笔记】《Pix2Pix》
    【论文阅读笔记】《DCGAN》
    【论文阅读笔记】《Conditional Generative Adversarial Nets》
    【论文阅读笔记】Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks
    【Datawhale】Python从入门到放弃
    【数字图像处理】 直方图的均衡与规定化
    GAN学习入门篇(一)
  • 原文地址:https://www.cnblogs.com/onlytiancai/p/dotnet_cursor_list.html
Copyright © 2011-2022 走看看