引言
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内存管理方法。
垃圾回收器
几乎所有目前流行的垃圾回收器,均倾向于将使用者当作一个傻瓜,期望能够让使用者在完全不理解内存管理的情况下,可以很好的使用它。应该说这它们基本上都也做到了(虽然使用者有时也有这样那样的烦恼,但总体来说情况确实得到了很大程度的改善)。然而这一设计理念我并不十分认同。
首先,可以在一个提供垃圾回收器的语言中自如的工作,没有被垃圾回收器所困扰,本身已经是很了不起的事情,他们绝对是非常聪明的人,而不是傻瓜。他们理解垃圾回收器的工作原理,选择它并且让它为他们工作,只是因为还有更重要的事情等着他们去做。必要的时候,他们需要有办法控制垃圾回收器,使它按照他们的意愿工作。因此,垃圾回收器的设计要点在于把使用者从烦琐的内存管理中解脱出来,使得他们可以将全部精力投入到本身的业务逻辑上,而不是让垃圾回收器看起来更傻瓜式。
其次,使用一个全自动的垃圾回收器,在内存回收的时机不明确的情况下,垃圾回收器的工作过程有很大的不确定性,这给使用者带来烦恼。例如C#在调用非管制代码(如调用Win32 api)时,这些问题变得突出。一个不小心,就有可能出现Win32 api还在使用一块内存,而垃圾回收器已经把它回收了的情形。在小心翼翼的避开这些陷阱时,这种感觉其实与C/C++程序员遗憾语言没有垃圾回收器的感觉有点类似。
因此,最理想的情况,是内存管理器提供垃圾回收的能力,但是它也只是提供这个能力而已,至于什么时候进行垃圾回收,完全可以由用户自己控制。另外,用户也可以强制释放一块内存,而不是完全被动的等待垃圾回收过程决策何时回收该内存。对于客户来说,他有权掌控一切,只是如果万一他确实疏忽了,垃圾回收器能够为他护航。
将垃圾回收器引入C++,有没有这种可能呢?我认为,如果我们试图提供一个全自动的垃圾回收器,这相当困难。我们看到以Microsoft之能,仍然无法把这件事做好。或许,我们需要改变一下观念:一个半自动的垃圾回收器,也许就可能可以和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 Type* New(AllocType& alloc); // 类似于new Type template Type* New(ArgType1 arg1, AllocType& alloc); // 类似于new Type(arg1) template Type* NewArray(size_t count, AllocType& alloc);// 类似于new Type[count] |
有了这些辅助函数,我们就可以创建对象了。使用样例:
SimpleAlloc alloc; int* intArray = NewArray(count, alloc); MyClass* obj = New(alloc); MyClass* objWithArg = New(arg1, alloc); MyClass* objArray = NewArray(count, alloc); |
这里我们虽然使用SimpleAlloc创建对象,但是需要提醒的是,这些New操作对所有的allocator有效。如果你关心New函数的代码,先不急,下面我们马上就可以看到了。但是首先我们要继续讨论一下allocator。www.goodsgy.com[1] [2] 下一页
|
|
|
|
在百度中搜索:涅磐重生 C++内存管理变革
在Google中搜索:涅磐重生 C++内存管理变革
在Yahoo中搜索:涅磐重生 C++内存管理变革 |
收藏到网摘:新浪VIVI
365key
我摘
POCO网摘
博采中心
YouNote
和讯网摘
天天收藏
|
|
|
|
[]
[返回上一页]
[打 印]
[收 藏] |
|
|
| ∷相关文章评论∷ (评论内容只代表网友观点,与本站立场无关!) [更多评论…] |
|
|
|
|