我想制作自己的malloc / free,这样我就可以制作精确的复制分配器。
任何大师都有任何提示和建议吗?
我现在有几个问题:
答案 0 :(得分:20)
有很多关于实现malloc和类似事物的好文献。但是我注意到你在这里包含C ++ - 你知道你可以在C ++中编写自己的new
和delete
实现吗?这可能很有用,可以轻松实现。
在任何情况下,您想要的特性将在很大程度上取决于您的工作量,即一段时间内的使用模式。如果你只有mallocs和new frees,很明显很简单。如果你只有一个或几个不同的块大小的malloc,那也很简单。
在其他语言中,你可以通过将内存链接在一起来获得一些优势,但C并不那么聪明。
malloc的基本实现只是分配一个包含数据长度的头,一个“使用中的标志”和一个malloced内存。然后,Malloc在其空间的末尾构造一个新的头,分配内存,并返回一个指针。当你空闲时,它只会重置使用中的标志。
诀窍在于,当你做了大量的mallooc和free时,你可以快速获得许多未使用但很难分配的小blob。所以你需要某种bumpo gc来合并内存块。
你可以做一个更复杂的gc,但要记住这需要时间;你不想自由地占用很多时间。
Solaris malloc实现上有一个nice paper,您可能会感兴趣。这是另一个on building an alternative malloc,同样在Solaris中,但基础是相同的。你应该阅读关于垃圾收集的Wikipedia article,然后关注一些更正式的文章。
你知道,你真的应该看看世代垃圾收集器。基本的想法是,分配的东西越长,保留分配的可能性就越大。这是你提到的“复制”GC的扩展。基本上,你在内存池的一个部分分配新东西,称之为g0。当你达到高水位标记时,你会查看已分配的块并将仍在使用的块复制到另一段内存中,将其称为g1,然后你可以清除g0空间并开始在那里分配。最终g1达到高水位,你通过清除g0来修复它,并清理g1移动到g0的东西,当你完成后,你将旧g1重命名为g0,反之亦然并继续。
诀窍在于,特别是在C语言中,你传递给malloc内存的句柄是直接的原始指针;如果没有一些大药,你就无法真正移动。
在评论中,@ badn提出“不会移动东西只是一个memcpy()”。事实上它会。但请考虑这个时间表:
警告:此操作尚未完成,未经测试,仅供参考,仅供娱乐,不提供明示或暗示保修
/* basic environment for illustration*/
void * myMemoryHdl ;
unsigned char lotsOfMemory[LOTS]; /* this will be your memory pool*/
你动画一些内存
/* if we get past this, it succeded */
if((myMemoryHdl = newMalloc(SIZE)) == NULL)
exit(-1);
在malloc的实现中,创建内存并返回指向缓冲区的指针。
unsigned char * nextUnusued = &lotsOfMemory[0];
int partitionSize = (int)(LOTS/2);
int hwm = (int) (partition/2);
/* So g0 will be the bottom half and g1 the top half to start */
unsigned char * g0 = &lotsOfMemory[0];
unsigned char * g1 = &lotsOfMemory[partitionSize];
void * newMalloc(size_t size){
void * rtn ;
if( /* memory COMPLETELY exhausted */)
return NULL;
/* otherwise */
/* add header at nextUnused */
newHeader(nextUnused); /* includes some pointers for chaining
* and a field with values USED or FREE,
* set to USED */
nextUnused += HEADERLEN ; /* this could be niftier */
rtn = nextUnused ;
nextUnused += size ;
}
有些东西被释放了
newFree(void * aHandle){
*(aHandle-offset) = FREE ; /* set the flag in the header,
* using an offset. */
}
所以现在你做了所有的事情,你就达到了高水位。
for( /* each block in your memory pool */ )
if( /* block header is still marked USED */ ) {
memcpy(/* block into other partition */);
}
/* clear the partition */
bzero(g0, partitionSize);
现在,返回您在myMemHdl中保存的原始句柄。它指向什么? (答案,你只需用bzero(3)将其设置为0x00。)
这就是魔法的来源。至少在C中,你从malloc返回的指针不再受你的控制 - 你不能在事后移动它。在C ++中,使用用户定义的类指针类型,您可以修复它。
答案 1 :(得分:1)
了解您正在尝试做的事情会更有帮助。这是单一类型吗?还是一套相对统一的类型?
tcmalloc的文档非常擅长描述这些技术的当前技术水平。
这里没有太多复杂的东西,但你可能正在重新发明 轮。有一些开源库可以做到这一点。
答案 2 :(得分:0)
不要使用想法#1,你会浪费大量资源,这些资源可能在整个应用程序的执行过程中可能仍未使用,同时阻止其他进程使用它(取决于你计划的数量)取)。