﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Gideon</title><link>http://www.cppblog.com/Gideon/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 09 Jun 2026 18:50:05 GMT</lastBuildDate><pubDate>Tue, 09 Jun 2026 18:50:05 GMT</pubDate><ttl>60</ttl><item><title>STL源码阅读1——内存分配</title><link>http://www.cppblog.com/Gideon/archive/2010/12/12/136244.html</link><dc:creator>Gideon</dc:creator><author>Gideon</author><pubDate>Sun, 12 Dec 2010 15:20:00 GMT</pubDate><guid>http://www.cppblog.com/Gideon/archive/2010/12/12/136244.html</guid><wfw:comment>http://www.cppblog.com/Gideon/comments/136244.html</wfw:comment><comments>http://www.cppblog.com/Gideon/archive/2010/12/12/136244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Gideon/comments/commentRss/136244.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Gideon/services/trackbacks/136244.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;文件Stl_alloc.h<br>&nbsp;文件内容介绍：此文件主要包含了为stl容器分配空间的一些函数，包括在内存溢出时&nbsp;<br>的一些相关处理。<br>&nbsp;&nbsp;&nbsp; 此文件前面进行系统类型的判断和是否使用多线程或者pthreads等判断<br>List：<br>名称&nbsp;类型&nbsp;返回值和参数&nbsp;功能<br>__malloc_alloc_template&nbsp;Class&nbsp;&nbsp;分配内存模板，模板带有一个模板参数为&lt;int inst&gt;,<br>为第一级配置<br>__malloc_alloc_template<br>::oom_malloc&nbsp;Function<br>private&nbsp;Return：Void*(表明分配的内存的地址)<br>Parm：size_t(表明要分配的内存的大小)&nbsp;分配内存函数，当内存出现溢出时调用oom--<br>out of memory。首先声明一个指针函数（其实这个指针函数在之前的模板中定义过<br>__malloc_alloc_oom_handler，当内存溢出时使用，其stl_alloc.h文件中给出的默认是0<br>，为空，当然用户也可以自己指定。alloc.h给出了处理函数__STD::<br>__malloc_alloc_oom_handler<br>）如果此函数指针仍然为空，则抛出分配内存异常，如果不为空则调用该函数，然后使用<br>malloc分配size_t大小的内存，将内存的首地址返回给此函数。在for<br>死循环中不断分配直到成功见C++ new-handler<br>__malloc_alloc_template<br>::oom_realloc&nbsp;Function<br>private&nbsp;Return :void*(表明分配的内存的地址)<br>Parm：void*(要重新分配的内存的地址)；size_t(重新分配内存的大小)&nbsp;<br>重新分配内存函数，当内存出现溢出时调用oom--out of memory<br>。首先声明一个指针函数（其实这个指针函数在之前的模板中定义过<br>__malloc_alloc_oom_handler，当内存溢出时使用，其stl_alloc.h文件中给出的默认是0<br>，为空，当然用户也可以自己指定。alloc.h给出了处理函数__STD::<br>__malloc_alloc_oom_handler<br>）如果此函数指针仍然为空，则抛出分配内存异常，如果不为空则调用该函数，然后使用<br>realloc分配size_t大小的内存，将内存的首地址返回给此函数。见C++ new-handler<br>__malloc_alloc_template::<br>__malloc_alloc_oom_handler&nbsp;Function pointer<br>Private&nbsp;Return：void<br>Parm：void&nbsp;如果在stl_config.h文件中define过__STL_STATIC_TEMPLATE_MEMBER_BUG<br>，那么声明这个函数指针，当分配内存出现错误的时候进行一些处理<br>__malloc_alloc_template::allocate&nbsp;Function<br>Public&nbsp;Return：void*(分配内存后的内存首地址)<br>Parm：size_t(需要分配的内存的大小)&nbsp;首先使用malloc分配size_t<br>大小的内存，如果分配成功，返回malloc返回值，如果失败则转到调用函数oom_malloc(<br>size_t)<br>__malloc_alloc_template::deallocate&nbsp;Function<br>Public&nbsp;Return:void<br>Parm:void*p(释放内存的指针)；size_t(未使用，表示p所指向的内存大小)&nbsp;调用free<br>释放参数一所指的内存<br>__malloc_alloc_template::reallocate&nbsp;Function<br>Public&nbsp;Return:void*(分配的内存的地址)<br>Parm:void*p(需要重新分配的内存地址内存的指针)；size_t(未使用，表示p原先的大小)<br>；sieze_t(表示新分配的内存大小)&nbsp;使用realloc进行重新分配内存，如果成功返回<br>realloc分配的内存的首地址，如果失败则调用函数oom_realloc函数处理<br>__malloc_alloc_template:: (* set_malloc_handler())&nbsp;Function<br>Public&nbsp;Return:void (*)()(返回原先的内存错误处理函数)<br>Parm:Void(*)()(内存出错处理函数)&nbsp;首先声明一个void(*old)()函数，将原先的<br>__malloc_alloc_oom_handler赋值给它，然后将f赋值给__malloc_alloc_oom_handler<br>，然后返回old。<br>注：此函数可以如此理解<br>typedef&nbsp; void (*fp)();<br>static fp set_malloc_handler(fp f);<br>如同fp为一个类型，然后声明f和set_malloc_handler变量一样，直接套进去就可以(<br>详见《C与指针》、《C专家编程》)<br>malloc_alloc&nbsp;Object&nbsp;&nbsp;typedef __malloc_alloc_template&lt;0&gt; malloc_alloc;<br>simple_alloc&nbsp;class&nbsp;&nbsp;简单的内存管理，含有模板参数&lt;class T, class Alloc&gt;，Alloc<br>表示的是一个内存管理的类型，如上面的__malloc_alloc_template<br>simple_alloc::allocate&nbsp;Function<br>Public、static&nbsp;Return：T*返回类型为T的内存指针<br>Parm：size_T<br>&nbsp;如果n==0，那么返回0，否则调用Alloc的allocate函数分配n*(sizeof(T))<br>大小内存，并强制转换为T(*)类型返回。<br>(将C中的分配特定类型的n个大小内存特化成一个函数)<br>simple_alloc::allocate&nbsp;Function<br>Public、static&nbsp;Return：T*返回指针类型为T的内存首地址<br>Parm：void&nbsp;重载上面的函数，返回大小为sizeof(T)的内存块，并强制转换成(T*)<br>指针返回<br>simple_alloc::deallocate&nbsp;Function<br>Public、static&nbsp;Return:void<br>Parm:T*(表示释放内存的首地址)；size_t(表示释放的类型为T的内存大小)&nbsp;如果n!=0<br>则调用Alloc的deallocate(p,sizeof(T)*n)进行内存释放<br>simple_alloc::deallocate&nbsp;Function<br>Public、static&nbsp;Return:void<br>Parm:T*(表示释放内存的首地址)&nbsp;则调用Alloc的deallocate(p,sizeof(T))进行内存释放<br>debug_alloc&nbsp;Class&nbsp;&nbsp;这个是为调试准备的，检查传入的size<br>参数是否符合特定的要求，使用assert<br>报告错误。如果没有检查的必要还是使用基本的内存分配器好点。带有一个模板参数&lt;<br>class Alloc&gt;<br>debug_alloc ::extra&nbsp;Enum<br>Private&nbsp;值为8&nbsp;存储空间的单位，应该足够大以保证内存对齐(对齐:从以n<br>为单位的地指处开始存取)<br>debug_alloc ::allocate&nbsp;Function<br>Public、static&nbsp;Return:void*(内存分配的首地址)<br>Parm:size_t n(分配的大小)&nbsp;使用Alloc::allocate分配n+extra个内存的大小(<br>我认为加上extra是为了防止n为0，看后面操作)，然后给这个内存的起始地址处赋值为n(<br>所以避免n为0时，内存错误)。然后以分配的地址+extra为返回值<br>debug_alloc :: deallocate&nbsp;Function<br>Public、static&nbsp;Return:void<br>Parm:void*p(为指向释放内存的地址)；size_t n(表示释放内存的大小)&nbsp;由于上面的<br>allocate在返回值上加了extra，所以在这里首先减去extra<br>，然后取出这个计算后的地址的值，用assert判断其是否和n相等(allocate存入的n)<br>，如果相等则使用Alloc(p,n+extra)释放内存<br>debug_alloc :: reallocate&nbsp;Function<br>Public、static&nbsp;Return:void*(内存分配的首地址)<br>Parm：void*p(需要重新分配内存的首地址);size_t old_sz(原先内存大小);size_t <br>new_sz(重新分配的内存的大小)&nbsp;前面两步如deallocate函数，只不过n换成old_sz<br>，然后使用Alloc函数reallocate重新分配内存(参数为p,old_sz+extra,new_sz+extra)<br>，并取得返回值result，并在result中放入值new_sz,最后返回result+extra地址<br>__ALIGN（全局）&nbsp;Enum&nbsp;8bytes&nbsp;<br>小型区块的上调边界（每一个小型区块指向一个一特定大小为单位的链表，详见表末说明 <br>。）<br>__MAX_BYTES（全局）&nbsp;Enum&nbsp;128bytes&nbsp;第一级配置器和第二级配置器的分界字节数<br>__NFREELISTS（全局）&nbsp;Enum&nbsp;__MAX_BYTES/__ALIGN&nbsp;Free-lists个数<br>__default_alloc_template&nbsp;Class&nbsp;&nbsp;STL<br>使用的是二级配置器，这个配置器是默认的。第一个模板参数是说明是否是多线程，类存?<br>渲檬窍叱贪踩模诙霾问ㄎ纯芍?<br>__default_alloc_template ::__ALIGN&nbsp;Enum<br>Private&nbsp;同全局&nbsp;如果全局中没有定义此enum，则在类中定义<br>__default_alloc_template ::__MAX_BYTES&nbsp;Enum<br>Private&nbsp;同全局&nbsp;同上<br>__default_alloc_template ::__NFREELISTS&nbsp;Enum<br>Private&nbsp;同全局&nbsp;同上<br>__default_alloc_template ::ROUND_UP&nbsp;Function<br>Private、static&nbsp;Return:size_t(在free_list中的节点的大小)<br>Parm:size_t bytes(要分配的内存大小)&nbsp;由于在free_list中维护的16个节点，而16<br>个节点的大小已经规定好，详见总结中 ，而分配的结果必须位于这16<br>个值当中，所以根据bytes传入的值的大小来取离此值最近的闭其大的值作为返回值。<br>__default_alloc_template :: obj&nbsp;Union<br>Private&nbsp;&nbsp;详见总结 <br>__default_alloc_template ::free_list&nbsp;private&nbsp;&nbsp;内存链<br>__default_alloc_template ::refill&nbsp;Private<br>Static&nbsp;Return:void*(地址)<br>Parm:sizet_t n(所要分配的内存块的大小)&nbsp;当allocate()发现freelist<br>中没有可用区块时，调用refill(),准备为freelist<br>重新填充空间，新的空间将取自内存池(经由chunk_alloc完成)缺省取得20<br>个新节点，但万一内存池空间不足，获得的节点数可能少于20<br>__default_alloc_template ::chunk_alloc&nbsp;Private<br>Static&nbsp;Return:char*(返回内存池分配的地址)<br>Parm:size_t size(内存块的大小);int&amp; nobjs(分配的块的个数)&nbsp;首先使用end_free，<br>first_free计算出当前情况下内存池共有的字节数bytes_left，然后判断，如果<br>bytes_left&gt;=*nobjs，那么就直接返回start_free的值，然后将start_free的值调整为<br>start_free+bytes_left.<br>如果内存池剩下的内存小于*nobjs,但是大于等于size，那么就分配bytes_left/size<br>个元素，调整start_free的值，返回start_free地址。如果内存池中的剩余地址小于size<br>，则首先产生一个 大于nobjs*2的值，将剩余的内存尽可能大的编进free list<br>里面。然后使用malloc分配内存，如果成功，调整heap_size，然后调整end_free<br>大小，返回值为重新调用自己产生的地址。如果malloc分配失败，则释放freelist<br>中较大的块，然后返回（调用自己）（如此循环）<br>__default_alloc_template :: start_free&nbsp;Private<br>Static&nbsp;Type:char*&nbsp;内存池的首地址，初值为0<br>__default_alloc_template :: end_free&nbsp;Private<br>Static&nbsp;Type:char*&nbsp;内存池的尾地址，初值为0<br>__default_alloc_template :: heap_size&nbsp;Private<br>Static&nbsp;Type: size_t&nbsp;内存池使用的堆栈大小，初值为0<br>__default_alloc_template :: __lock&nbsp;Private<br>&nbsp;Return:void<br>Parm:unsigned long*&nbsp;加锁，详细未查<br>__default_alloc_template :: __unlock&nbsp;Private&nbsp;Return:void<br>Parm:unsigned long*&nbsp;解锁，详细未查<br>Friend class lock&nbsp;&nbsp;属于__default_alloc_template的内部类&nbsp;构造函数调用<br>__NODE_ALLOCATOR_LOCK宏，而这个函数调用__lock(&#8230;),析构函数调用<br>__NODE_ALLOCATOR_UNLOCK宏，而这个宏调用__unlock(&#8230;)函数<br>注:类型为类、函数、仿函数等等，如果是成员函数则在名称前加上所属类并在类型上写上<br>其权限，总之名称包括可以唯一确定该元素<br>内存图：<br><img border=0 src="http://www.cppblog.com/images/cppblog_com/gideon/STL.jpg"><br>
<img src ="http://www.cppblog.com/Gideon/aggbug/136244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Gideon/" target="_blank">Gideon</a> 2010-12-12 23:20 <a href="http://www.cppblog.com/Gideon/archive/2010/12/12/136244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>