• C++内存管理变革


    C++内存管理变革 收藏


    C++内存管理变革

    许式伟
    2005-7-16
    关键字: 内存管理 垃圾回收器 内存配置器 引用计数
    keyword: memory manage, memory recycler, allocator, reference count
     
     
    引言
    C/C++语言的内存管理经历了几次变革,但至今仍未能趋于成熟。这几次变革主要包括:
     
    1.         从malloc/free到new/delete。这场变革是OOP技术兴起的产物。C++是强类型语言,new/delete的主要成果也就是加强了类型观念,减少了强制类型转换的需求。但是从内存管理角度看,这个变革并没有多少的突破性。
     
    2.         从new/delete到内存配置器(allocator)。自从STL被纳入C++标准库后,C++世界产生了巨大的变化。而从内存管理角度来看,allocator的引入也是C++内存管理一个突破。留意一下你就可以发现,整个STL所有组件的内存均从allocator分配。也就是说,STL并不推荐使用new/delete进行内存管理,而是推荐使用allocator。

    然而,STL的allocator并没有导致C++语言在内存管理上发生巨大的变化。除了STL本身外,并没有多少人使用allocator,甚至是意识到allocator的重要性。所以C++程序员在使用STL的同时,依旧在使用new/delete进行烦琐的内存分配/释放过程。

    究其原因,主要有二。一是allocator的引入,STL设计者主要可能还是出于将内存管理从容器的实现独立出来的设计理念作用,让STL使用者在内存管理算法上有选择的余地。设计者本身都可能也没有意识到allocator的重要性。二是allocator本身也只是侧重于关注效率上,而没有侧重于C++语言使用者对内存管理观念的变革上。
     
    总之,在我看来,STL的引入allocator,是一件了不起的事情。但是这场变革被忽视了,没有得到贯彻。当然,这也与STL的allocator本身的缺陷有关。
     
    本文要讨论的,正是如何贯彻STL的allocator思想,对其进行适当的改进,以期在C++内存管理观念上产生变革性的突破,彻底淘汰传统的new/delete内存管理方法[1]
     
     
    垃圾回收器
    几乎所有目前流行的垃圾回收器,均倾向于将使用者当作一个傻瓜,期望能够让使用者在完全不理解内存管理的情况下,可以很好的使用它。应该说这它们基本上都也做到了(虽然使用者有时也有这样那样的烦恼,但总体来说情况确实得到了很大程度的改善)。然而这一设计理念我并不十分认同。
     
    首先,可以在一个提供垃圾回收器的语言中自如的工作,没有被垃圾回收器所困扰,本身已经是很了不起的事情,他们绝对是非常聪明的人,而不是傻瓜。他们理解垃圾回收器的工作原理,选择它并且让它为他们工作,只是因为还有更重要的事情等着他们去做。必要的时候,他们需要有办法控制垃圾回收器,使它按照他们的意愿工作。因此,垃圾回收器的设计要点在于把使用者从烦琐的内存管理中解脱出来,使得他们可以将全部精力投入到本身的业务逻辑上,而不是让垃圾回收器看起来更傻瓜式。
     
    其次,使用一个全自动的垃圾回收器,在内存回收的时机不明确的情况下,垃圾回收器的工作过程有很大的不确定性,这给使用者带来烦恼。例如C#在调用非管制代码(如调用Win32 api)时,这些问题变得突出。一个不小心,就有可能出现Win32 api还在使用一块内存,而垃圾回收器已经把它回收了的情形。在小心翼翼的避开这些陷阱时,这种感觉其实与C/C++程序员遗憾语言没有垃圾回收器的感觉有点类似。
     
    因此,最理想的情况,是内存管理器提供垃圾回收的能力,但是它也只是提供这个能力而已,至于什么时候进行垃圾回收,完全可以由用户自己控制。另外,用户也可以强制释放一块内存,而不是完全被动的等待垃圾回收过程决策何时回收该内存。对于客户来说,他有权掌控一切,只是如果万一他确实疏忽了,垃圾回收器能够为他护航。
     
    将垃圾回收器引入C++,有没有这种可能呢?我认为,如果我们试图提供一个全自动的垃圾回收器,这相当困难。我们看到以Microsoft之能,仍然无法把这件事做好[2]。或许,我们需要改变一下观念:一个半自动的垃圾回收器,也许就可能可以和C++融洽相处了呢?
     
     
    初识allocator
    allacator中文称为“内存配置器”,通常它是一个类,负责提供内存管理(可能包含内存分配、释放、自动回收等能力)相关的服务。例如,我们通过C提供的malloc/free即刻提供一个allocator实作出来:
     
    class SimpleAlloc
    {
    public:
        //注意这里提供的参数fnDestroy,它是为那些具备垃圾回收能力的allocator需要提供。
    void* Alloc(size_t cb, FnDestructor fnDestroy = NULL)
        {
            return malloc(cb);
        }
     
        //注意这里有看似多余的参数cb,这完全是为了和后续提供的allocator规格一致的需要。
        void Free(void* data, size_t cb)
        {
            free(data);
        }
    };
     
    有了allocator,我们可以申请内存了,但是我们还不能用它创建一个C++对象。为了方便创建C++对象,我们提供了辅助的New操作,原型大体如下:
     
    template <class Type, class AllocType>
    Type* New(AllocType& alloc);                    // 类似于new Type
     
    template <class Type, class ArgType1, class AllocType>
    Type* New(ArgType1 arg1, AllocType& alloc); // 类似于new Type(arg1)
     
    template <class Type, class AllocType>
    Type* NewArray(size_t count, AllocType& alloc);// 类似于new Type[count]
     
    有了这些辅助函数,我们就可以创建对象了。使用样例:
     
    SimpleAlloc alloc;
    int* intArray = NewArray<int>(count, alloc);
    MyClass* obj = New<MyClass>(alloc);
    MyClass* objWithArg = New<MyClass>(arg1, alloc);
    MyClass* objArray = NewArray<MyClass>(count, alloc);
     
    这里我们虽然使用SimpleAlloc创建对象,但是需要提醒的是,这些New操作对所有的allocator有效。如果你关心New函数的代码,先不急,下面我们马上就可以看到了。但是首先我们要继续讨论一下allocator。
     
     
    allocator引起的观念变化
    接触allocator,你可以体会到了它与C++传统的new/delete观念的不同。这主要有以下几点:
     
    1.         每个类(或者算法)本身,均有最合适它的内存管理机制,并不是向C++传统的做法那样,使用一个全局的new/delete。也许你会说,C++不也允许一个类定义自己的new和delete吗?是的,C++的确支持类定义自己的new/delete,但注意,它的理念和allocator完全不同。我不认为它是C++的一个优秀之作,相反,它起到了误导作用。

    因为,决定一个类对象怎么去new出来,并不是取决于该类本身,而相反是取决于使用该类的人。一个类不需要关心自身被如何创造出来,更不能假定。它需要关心的是它自己的类成员如何被创建出来,它的算法(你可以把类看做一个算法集合)涉及到的所有组件如何被创建出来。而这,才是allocator带来的观念。

    让各种各样的allocator创建同一个类的不同实例,这些实例甚至可能在一起工作,相互协作。从STL的角度讲,这完全是最正常不过的事情了。
     
    2.         重要的是由allocator创建管理对象,避免在你的代码中使用new/delete。如果可能,你可以如STL那样,将allocator作为模板参数,不绑定具体的某个内存管理器。但是,如果你的算法依赖了某个allocator的实现特有的功能,这也并不要紧。你的目的不是要做到allocator的可替换,不是吗?重要的是使用了这个allocator了,它给你在内存管理上带来了益处。
     
    但是,应该看到,STL实作的各种allocator,目前来看除了最简单使用malloc/free实现的外,主要就是基于mempool技术。而该技术的目标,不是让内存使用者更加方便有效地进行内存管理,而更多的是关注于内存分配的时间性能。为了让C++程序员从内存管理中解脱出来,我们需要实作新的alloctor,需要新的突破!
     
     
    新视角:具垃圾回收能力的Allocator
     
    对,我设想的一个做法是,贯彻STL的allocator观念,并且提供具备特定的内存管理能力(例如垃圾回收)的各种allocator。让C++社区广泛接受allocator观念,并且从中受益。C++程序员是时候抛弃传统的new/delete,让他们退出历史舞台了。
     
    我接下来会实作两个具体的allocator(均属原创)。相信它们会让你耳目一新,让你不禁想到:哦,原来在C++中,我还可以这样进行内存管理。
     
    当然,我最大的希望就是,这两个allocator能够起到抛砖引玉的作用,让大家也清楚地意识到allocator的重要性,可以出现更多的具备各种能力的allocator,解脱C++程序员一直以来的苦难(可能是最大苦难[3])。
     
    这两个allocator均具备一定程度的垃圾回收能力。只是观念上各有各的侧重。我们接下来会分为两个专题专门对它们进行阐述。
     
     
    辅助的New过程
    我们终于可以开始讨论前文提到的New函数的实现上了。以不带参数的New为例,它的代码如下,可能并没有你想象的那么复杂:
     
    #include <new>
     
    template <class Type, class AllocType>
    inline Type* New(AllocType& alloc)
    {
        void* obj = alloc.Alloc(sizeof(Type), DestructorTraits<Type>::Destruct);
        return new(obj) Type;
    }
     
    其中DestructorTraits是一个根据类型Type萃取[4]析构函数的萃取器。它看起来是这样的:
    template <class Type>
    struct DestructorTraits
    {
        static void Destruct(void* pThis)
        {
            ((Type*)pThis)->~Type();
        }
    };
     
    这样,你就可以通过以下代码new出对象了:
    MyClassA* obj = New<MyClassA>(alloc);
    MyClassB* obj = New<MyClassB>(alloc);
     
    特别提醒:这里New函数在VC++ 6.0下编译通过,但是产生的执行代码存在严重bug。如果你只New一类对象,没有问题,但在New了多种对象后,似乎VC++对MyClassAMyClassB 两者混淆起来了。为了支持VC++ 6.0,你需要对这里的New做出调整(关于这一点,详细请参考:VC++ 6.0小技巧)。
     
     
    COM技术[5]与内存管理
     
    已经准备结束这篇短文的时候,忽然想到了长久以来使用COM技术形成的一些感想,这些想法恰恰与内存管理紧密相关。故此想就这个问题陈述一下。
     
    从COM的IUnknown接口看,它主要关注两个问题:一个是QueryInterface,一个是引用计数(AddRef/Release)。COM组件很讲究信息的屏蔽,使用者对组件的认识有限,这就给组件升级、扩充功能提供了可能。QueryInterface是一个很好的概念,需要发扬光大。
     
    COM的引用计数则关注的是组件的生命期维护问题。换句话说,就是组件如何销毁的问题。诚然,组件对象的销毁问题,是内存管理的关键。无论是COM的引用计数,还是垃圾回收技术,均是要解决对象的销毁问题。只是两者的侧重点不太一样,COM引用计数更关注“确保组件不会被提前销毁了,确保组件访问的安全性”,而垃圾回收器则关注“不管怎样确保组件最终被销毁,没有内存泄漏”。
     
    在COM中,确保组件访问的安全性(避免非法访问),这个观点太重要了,以至于它甚至不惜加重程序员的内存管理负担。所以,在COM程序中,出现内存泄漏太正常了,而且一旦泄漏通常就是大片大片内存的漏。更加要命的是,你甚至不能有一个很简单有效的方法确认这个泄漏是由于哪段代码引起。因为组件所有的客户都是平等的,任何一个客户代码存在问题均将导致内存的泄漏。
     
    刚开始接触COM技术的时候,我对引用计数持的是比较正面的态度。但是随着部门逐步加大COM技术的使用力度后,四五年下来,我渐渐开始迷惑起来。一切并不如想象的那样。这个引用计数的背后,需要我们付出多少额外的代价!
     
    而这个迷惑、思索,可能就是本文以及后续相关内容的成因吧。


    [1] 如果大家对本文观点有任何不同意见,或者有什么需要和我探讨的,欢迎联系:xushiweizh@gmail.com
    [2] Microsoft的财力实力是有目共睹的。然而它在VC++中进行管制代码的尝试,看起来并不怎么成功。而且就以Microsoft之能,也无法把经典的C++的非管制代码与管制代码融合的很好。我想,我们不应该再钻这个死胡同了。
    [3] 当然,也许C++另一个致命伤是没有一个标准的图形/界面库。然而毕竟还是有那些形形色色的界面库支撑着。而内存管理,似乎是C++有生俱来的缺陷,没有得到应有的重视。
    [4] 萃取,英文traits,是C++模板特化技术应用的一个典范,被stl、boost等库广泛使用。
    [5] COM技术贯穿于Microsoft所有的产品之中并带来了巨大的成功。要了解COM技术,有不少好书,如《COM本质论》、《COM技术内幕》等等。
      

    发表于 @ 2006年11月16日 21:41:00 | 评论( 42 ) | 举报| 收藏

    旧一篇:VC++ 6.0的小花招 | 新一篇:PV突破2万

     

    mcs51a 发表于Fri Nov 17 2006 09:28:00 GMT+0800 (China Standard Time)  举报回复删除
    COM的对象引用记数只是保证多线程对象的生存周期,与内存管理有什么关系? 
    std::allocator的作用也不是内存管理这么简单. 

    你能确定你的程序运行性能问题是由new/delete引起的? 

    to mcs51a 发表于Fri Nov 17 2006 09:58:00 GMT+0800 (China Standard Time)  举报回复删除
    频繁的new/delete会造成内存碎片 
    allocator使用mempool的方式,效率要好得多
    to mcs51a 发表于Fri Nov 17 2006 10:02:00 GMT+0800 (China Standard Time)  举报回复删除
    频繁的new/delete会造成内存碎片 
    allocator使用mempool的方式,效率要好得多
    hehe 发表于Fri Nov 17 2006 10:04:00 GMT+0800 (China Standard Time)  举报回复删除

    “因此,最理想的情况,是内存管理器提供垃圾回收的能力,但是它也只是提供这个能力而已,至于什么时候进行垃圾回收,完全可以由用户自己控制。另外,用户也可以强制释放一块内存,而不是完全被动的等待垃圾回收过程决策何时回收该内存。对于客户来说,他有权掌控一切,只是如果万一他确实疏忽了,垃圾回收器能够为他护航。” 

    这个说法我觉得有些片面。作者仅考虑了语言,而没有考虑语言所要服务的目标系统。内存管理可能更是目标环境要绝对控制的方面,呵呵,作为一种灵活的语言,要考虑和各种目标系统融洽。 


    “因为,决定一个类对象怎么去new出来,并不是取决于该类本身,而相反是取决于使用该类的人。一个类不需要关心自身被如何创造出来,更不能假定。它需要关心的是它自己的类成员如何被创建出来,它的算法(你可以把类看做一个算法集合)涉及到的所有组件如何被创建出来。而这,才是allocator带来的观念。” 

    这一句有些武断,可能是另外一种“误导”呢,呵呵,如果按照作者说的方向去发展,C++就不会那么灵活了。其实,new/delete和alloc/free并不如此的不相容,前者只是稍多考虑了面向对象时的构造和析构,而且可以被重写。到底需要用什么方式去使用内存,需要C++程序员,在实际环境下作出决定。 

    另外,关于COM,我还是持正面态度的。它的引用计数规则,已经简单得不能再简单了。COM的不足不在这里,关于不足,DonBox的看法是比较深刻的。另外,推荐你看看这个小短文 http://blog.csdn.net/codesigner/posts/1261485.aspx 
    hehe 发表于Fri Nov 17 2006 10:13:00 GMT+0800 (China Standard Time)  举报回复删除

    “因此,最理想的情况,是内存管理器提供垃圾回收的能力,但是它也只是提供这个能力而已,至于什么时候进行垃圾回收,完全可以由用户自己控制。另外,用户也可以强制释放一块内存,而不是完全被动的等待垃圾回收过程决策何时回收该内存。对于客户来说,他有权掌控一切,只是如果万一他确实疏忽了,垃圾回收器能够为他护航。” 

    这个说法我觉得有些片面。作者仅考虑了语言,而没有考虑语言所要服务的目标系统。内存管理可能更是目标环境要绝对控制的方面,呵呵,作为一种灵活的语言,要考虑和各种目标系统融洽。 


    “因为,决定一个类对象怎么去new出来,并不是取决于该类本身,而相反是取决于使用该类的人。一个类不需要关心自身被如何创造出来,更不能假定。它需要关心的是它自己的类成员如何被创建出来,它的算法(你可以把类看做一个算法集合)涉及到的所有组件如何被创建出来。而这,才是allocator带来的观念。” 

    这一句有些武断,可能是另外一种“误导”呢,呵呵,如果按照作者说的方向去发展,C++就不会那么灵活了。其实,new/delete和alloc/free并不如此的不相容,前者只是稍多考虑了面向对象时的构造和析构,而且可以被重写。到底需要用什么方式去使用内存,需要C++程序员,在实际环境下作出决定。 

    另外,关于COM,我还是持正面态度的。它的引用计数规则,已经简单得不能再简单了。COM的不足不在这里,关于不足,DonBox的看法是比较深刻的。另外,推荐你看看这个小短文 http://blog.csdn.net/codesigner/posts/1261485.aspx 
    mcs51a 发表于Fri Nov 17 2006 11:22:00 GMT+0800 (China Standard Time)  举报回复删除
    allocator引起的观念变化? 
    有吗? 

    operator new ,operator delete 是可以重载的啊
    mcs51a 发表于Fri Nov 17 2006 13:36:00 GMT+0800 (China Standard Time)  举报回复删除
    “算法”可以选择内存管理算法? 准确的说法应该是“容器”可以选择某种特定地址管理方法吧.和operator new/operator delete的思想 ,有什么不同吗?没有.应该说思想是有异曲同工之妙,operator new/operator delete哪来的误导?有启发才对. 

    mcs51a 发表于Fri Nov 17 2006 13:49:00 GMT+0800 (China Standard Time)  举报回复删除
    COM引入引用计数,这个引用计数的背后,需要我们付出“惨重”的代价。有什么“惨重”的代价? 
    com本来就不是为C++准备的 
    xushiwei 发表于Fri Nov 17 2006 13:51:00 GMT+0800 (China Standard Time)  举报回复删除
    是的,我是说,“算法”可以选择内存管理算法。为什么类实现时需要考虑使用什么allocator?是因为类是一组算法的集合,我们要为这些“算法”选择allocator。
    xushiwei 发表于Fri Nov 17 2006 13:06:00 GMT+0800 (China Standard Time)  举报回复删除
    to mcs51a: 

    1、allocator的引入,STL设计者主要可能还是出于将内存管理从容器的实现独立出来的设计理念作用,让STL使用者在内存管理算法上有选择的余地。 

    2、“内存碎片”是技术细节,本文未讨论。 

    3、相对new/delete,allocator当然引起的观念变化。因为new/delete的观念,是“类”可以选择内存管理算法;allocator的观念,是“算法”可以选择内存管理算法。我认同allocator的观点。c++允许类重载new/delete,是个误导。
    xushiwei 发表于Fri Nov 17 2006 13:54:00 GMT+0800 (China Standard Time)  举报回复删除
    而C++类的new/delete,是为使用这个类的客户选择内存管理算法,而类对其客户是一无所知的。脱离了算法而去选择如何管理内存,这是一种很强的误导。
    xushiwei 发表于Fri Nov 17 2006 13:16:00 GMT+0800 (China Standard Time)  举报回复删除
    to hehe: 

    关于COM,我亦是持正面态度的。你介绍的的短文我看了。我很认同该文的观点。尤其是COM与.NET关系,我也有类似的提法,参考“ATL界面类——兼谈多态与泛型”。 

    COM引入引用计数,是非常可以理解的。本文并不想详细论述COM的方方面面,只是从内存管理角度讨论引用计数。无疑,这个引用计数的背后,需要我们付出“惨重”的代价。
    mcs51a 发表于Fri Nov 17 2006 13:58:00 GMT+0800 (China Standard Time)  举报回复删除
    QueryInterface是COM最丑陋的地方.QueryInterface属于过于FAT的东西
    xushiwei 发表于Fri Nov 17 2006 13:21:00 GMT+0800 (China Standard Time)  举报回复删除
    to mcs51a: 

    引用计数则关注的是组件的生命期维护问题。换句话说,就是组件对象如何销毁的问题。对象的销毁问题,不是内存管理是什么?
    wangdong 发表于Fri Nov 17 2006 14:03:00 GMT+0800 (China Standard Time)  举报回复删除
    呵呵,感觉他们就没怎么用过这些东西。
    mcs51a 发表于Fri Nov 17 2006 14:13:00 GMT+0800 (China Standard Time)  举报回复删除
    呵呵,你强调的无非是由调用者 决定类的 new/delete 方式了.但是operator new/operator delete也没有误导你啊. 


    不再回复了,没有意义. 

    xushiwei 发表于Fri Nov 17 2006 15:01:00 GMT+0800 (China Standard Time)  举报回复删除
    是的,由调用者决定类的new/delete方式,还是类自己决定new/delete方式,这是两个完全不同的思考模式。所以,从new/delete到allocator,这是一大变革。
    mcs51a 发表于Fri Nov 17 2006 11:13:00 GMT+0800 (China Standard Time)  举报回复删除
    内存碎片 ,是由于同时分配很多小的对象,而不释放,导致2g的地址空间没有地址可以分配.没想象的那么严重吧. :) 
    mcs51a 发表于Fri Nov 17 2006 11:18:00 GMT+0800 (China Standard Time)  举报回复删除
    内存碎片引起的性能问题,恐怕也不是垃圾回收所能完全解决的吧? 
    : )
    xushiwei 发表于Fri Nov 17 2006 21:17:00 GMT+0800 (China Standard Time)  举报回复删除
    请注意,我是说类的new/delete可重载,是种误导,而非说operator new/delete本身。
    liigo博客专家 发表于Sun Nov 19 2006 18:33:00 GMT+0800 (China Standard Time)  举报回复删除
    “几乎所有目前流行的垃圾回收器,均倾向于将使用者当作一个傻瓜,期望能够让使用者在完全不理解内存管理的情况下,可以很好的使用它。” 

    所谓的“傻瓜式**”,只不过是一种大众的、通俗的说法,显然并不是把用户当作傻瓜。把复杂的事情透明化,减少用户的关注点,大多数情况恰恰是对用户的尊重。当然,除了傻瓜相机,还有单反相机,用户可以在两者之间做出选择。
    xushiwei 发表于Sun Nov 19 2006 20:17:00 GMT+0800 (China Standard Time)  举报回复删除
    to fnzh: 是的,allocator比new/delete要高明多。但是,似乎我们中没有人用allocator去管理内存,这不是很值得思考吗?
    fnzh 发表于Sun Nov 19 2006 15:39:00 GMT+0800 (China Standard Time)  举报回复删除
    new/delete是否误导可能从不同的角度来看可能会得出不同的结论。从面向对象角度来看,类确实不该去干涩自己在哪儿被创建,这应该由用户去决定;然而从c++设计者角度来看,他们是希望c++能足够灵活强大,能满足各种需要,并不太在意是否违背面向对象原则,说实在的c++本身就不是一种纯面向对象语言。 

    说起allocator,当然比类重载new/delete要高明许多。期待许先生的具垃圾回收能力的Allocator!
    inwind 发表于Mon Nov 20 2006 11:39:00 GMT+0800 (China Standard Time)  举报回复删除
    xushiwei 发表于2006-11-19 20:17:00 IP: 219.131.180.* 
    to fnzh: 是的,allocator比new/delete要高明多。但是,似乎我们中没有人用allocator去管理内存,这不是很值得思考吗? 

    同意
    xushiwei 发表于Mon Nov 20 2006 17:36:00 GMT+0800 (China Standard Time)  举报回复删除
    to ricardo: 呵呵,可不可以给我描述一下boost::pool好在哪里?
    肉骨头 发表于Tue Nov 28 2006 23:39:00 GMT+0800 (China Standard Time)  举报回复删除
    allocator是一种policy,而不是service。 

    两者有本质的区别。 

    以service的思维来实现一个allocator会让事情变得复杂。
    soplwang 发表于Wed Dec 06 2006 13:49:05 GMT+0800 (China Standard Time)  举报回复删除
    我是个 JAVA 程序员,最近因为一个个人项目里用到 C++,因而又捡起 C++ 。 但是一直想找个在 C++ 里简单可用的 GC,HP 的 GC 太复杂了,且个人觉得也并不必要。后来找到 boost::pool / object_pool,使用起来的确感觉很好。 今天看到 许先生 的 allocator ,觉得在某些方面上的确比 boost::pool 要好。 许先生的 allocator ,在一个不断申请内存,且不需要释放/很少释放的情境下,效率非常之好。而 boost::pool 则更适合在 scope 中既有需要 申请,也有相当数量的 释放 的情境。 两者各有自己的所长,世间本来就不可能有完美解决方案的。 ----- 我觉得两个都很好,只是需要看场景来使用罢了。。。
    soplwang 发表于Wed Dec 06 2006 14:03:07 GMT+0800 (China Standard Time)  举报回复删除
    但我也要说一句,既然 boost::pool 存在,那么具垃圾回收能力的Allocator 也就并不能算新视角了耶。。。
    soplwang 发表于Wed Dec 06 2006 14:55:02 GMT+0800 (China Standard Time)  举报回复删除
    不过,许先生的这种实现的确是更像 GC。
    soplwang 发表于Wed Dec 06 2006 15:46:11 GMT+0800 (China Standard Time)  举报回复删除
    http://www.cantrip.org/wave12.html?seenIEPage=1 穷人的 GC
    soplwang 发表于Wed Dec 06 2006 16:05:24 GMT+0800 (China Standard Time)  举报回复删除
    经过查看 STL 的资料,发现,STL 并不是没考虑过 GC 式 allocator,而却是因为那样的话,违反了STL 的 1) 值 语义,2)对象应由其`所有者`管理原则(整体对部分负全责)。
    GC 式 allocator 我所能看到的最早的文档是1993 年的。因此,最迟这个技术也不会迟于 1993 即已经出现。
    STL 显然是将 allocator 设计为 policy,而不是 element 的托管容器。
    soplwang 发表于Wed Dec 06 2006 16:06:49 GMT+0800 (China Standard Time)  举报回复删除
    当然,STL 也不适合用一种 永不释放 的 allocator 来实现。
    soplwang 发表于Wed Dec 06 2006 16:24:06 GMT+0800 (China Standard Time)  举报回复删除
    记得 Efficent C++ 里也有 可变内存池 的实现,可惜许久前看的,记不清了。只是推测,它应该没有 boost::pool 的第一次分配时的 初始化 动作。
    soplwang 发表于Wed Dec 06 2006 19:13:00 GMT+0800 (China Standard Time)  举报回复删除
    唉,想得累了,再补充一点:
    许先生,应该发现,加入 对象回收(不是指内存回收, 有很重要的差别) 功能的 分配器(allocator) 已经不再是一个 分配器 了。它有一个更正确的名字,叫 对象池(object pool)。
    只是,许先生的实现,称为 仅分配无释放快速对象池,典型的 空间 换 时间 算法。
    我觉得,还是应该将 allocator 名字回归到其应有的位置。它是一个内存分配的 policy,不应在其中实现 对象 的 所有权 语义。
    Anyway, 我还是在用 许先生 的 快速对象池,因为,真的很好用。
    soplwang 发表于Wed Dec 06 2006 19:15:03 GMT+0800 (China Standard Time)  举报回复删除
    11. new/delete 操作符重载通常只用于实现特殊的内存分配算法。仅当 特定类 有特殊需求时,才实现对于该 类 的 new/delete 运算符重载,此时,应该与 allocator 概念协作,以提供高度的灵活性 —— 设计模式。new/delete 实现界面,allocator 实现行为;
    xushiweizh博客专家 发表于Thu Dec 07 2006 00:48:21 GMT+0800 (China Standard Time)  举报回复删除
    to soplwang: 你想得很仔细。有空聊聊。我的联系方式blog上有。
    xushiweizh博客专家 发表于Thu Dec 07 2006 00:50:06 GMT+0800 (China Standard Time)  举报回复删除
    boost::pool只是allocator,不是我说的gc allocator,它们是不同的。boost::object_pool更像一个gc allocator,但是不够通用,只能分配一种对象,所以也不能算正真意义上的gc allocator。
    xushiweizh博客专家 发表于Thu Dec 07 2006 00:51:01 GMT+0800 (China Standard Time)  举报回复删除
    我本来要写后文,最近忙,没有机会整理。看过几天抽空继续写下面的。
    yxmmrwx 发表于Fri Mar 07 2008 23:12:49 GMT+0800 (China Standard Time)  举报回复删除
    路过的,看到这里的对答都相当深奥,想必对C/C++功力

    已达N重境界,可喜可贺!
    用C++也有些年头了,可以说已经到了非C++不用的执着

    !
    又苦于C++GUI过程的烦!因此时常想自己动手偿试一个

    C++GUI RAD方案,而且也确有实作过demo.感觉如果暂

    不提效率问题的话(因为效率问题我真不知如何计算和

    评估).
    应该可以kill掉现有的许多重量级GUI库.将许多因GUI

    苦恼而弃C++的程序员重新拉回C++阵营.我确信如果没有

    GUI的困扰的话,用C++写程序将会很愉快!刚好看到

    lanzhengpeng2的提问,所以顺便提一下.我目前是在

    MFC下实现的(有一种在人家的GUI上占空子的嫌疑),但

    要在SDK下实现也应没有问题.希望看到本文的各路前

    辈后进发表下看法,如果有此解决方案,你需要吗?如果

    需要的人多了,我就考虑跳出来完成它(我还在为三餐

    努力中^_^)
    参与讨论的方法如下:
    把你向往的GUI库或你需要实现的功能罗列出来,看我

    的方案能否kill掉它.
    联系:yxmmrwx@hotmail.com
    yxmmrwx 发表于Fri Mar 07 2008 23:35:01 GMT+0800 (China Standard Time)  举报回复删除
    一名话,如果让你不用写一行代码就可实现BCB能够做到的RAD方案(仅就GUI而言),你需要吗?
    yxmmrwx 发表于Fri Mar 07 2008 23:37:05 GMT+0800 (China Standard Time)  举报回复删除
    且操作过程全程wysiswyg
  • 相关阅读:
    Unity中溶解shader的总结
    Unity Shader 知识点总结(二)
    Unity Shader 知识点总结(一)
    Unity优化之GC——合理优化Unity的GC
    nuxt中使用vant框架
    Redux第一节
    React动画库
    react一写工具
    几种下载第三方的方式有何不同
    React生命周期函数
  • 原文地址:https://www.cnblogs.com/blockcipher/p/2913030.html
Copyright © 2020-2023  润新知