2024年C C++最新开发成长之路(6)-- C++从入门到开发(C,2024年最新终于搞明白了


网上学习资料种类繁多,在线课程琳琅满目。然而若所学知识缺乏系统性,在面对问题时常是蜻蜓点水式地接触,无法深入探究,那么就难以实现真正的技术突破。
想要这份系统化的资料的朋友,请访问这个链接获取
一个人的速度很快;却一个群体则能够走得更远!无论你是资深从业者还是热爱IT行业的新人,我们都欢迎您加入我们的平台/社群(技术交流群组、学习资源分享区、职场吐槽&内部推荐渠道、大厂人才直通会、面试辅导班),让我们共同成长进步!
#include
//注意,alloc不接受“template 型别参数”,所以就算你定义了也用不上
class __malloc_alloc_template
{
private: //这里面都是函数指针,用来处理内存不足的情况
static void *oom_malloc(size_t);
static void *oom_realloc(void *,size_t);
static void (* __malloc_alloc_oom_handler)();
public:
//正常空间配置
static void * allocate(size_t n)
{
void *result = malloc(n);
if( 0 == result)
result = oom_malloc(n);
return result;
}
//正常空间回收
static void deallocate(void *p,size_t /n /)
{
free§;
}
//正常重分配空间
static void * reallocate(void p,size_t / old_sz */,size_t new_sz)
{
void * result = realloc(p,new_sz);
if( 0 == result )
result = oom_realloc(p,new_sz);
return result;
}
}
//截取片段,留作向后拓展的部分这里就不提了
//下面为异常情况处理(空间不够)
void *__malloc_alloc_tempate<0>::oom_malloc(size_t n)
{
void (* my_malloc_handler)();
void *result;
for(;😉
{
//不断尝试释放、配置、再释放、再配置
my_malloc_handler = __malloc_alloc_oom_handler;
if( 0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(* my_malloc_handler)(); //调用处理例程,企图释放内存
这一行看起来让我感到困惑。在查阅的相关资料中确实提供了有力的支持,"调用用户定义函数"。然而,"用户"在这里指的是处理例程而不是我们自己。
//如果有更好的理解,万望不吝赐教。
result = malloc(n); //尝试再次配置内存
if(result)
return (result);
}
void *__malloc_alloc_tempate<0>::oom_realloc(void *p,size_t n)
{
void (* my_malloc_handler)();
void *result;
for(;😉
{
//不断尝试释放、配置、再释放、再配置
my_malloc_handler = __malloc_alloc_oom_handler;
if( 0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(* my_malloc_handler)();
result = realloc(p,n); //尝试再次配置内存
if(result)
return (result);
}
SGI使用malloc而非::operator new来分配内存。这源于长期的技术积累,并受到频繁内存重新配置的影响。
c.3 alloc 二级配置器源码(截取)
如果累了,建议先歇会儿,保护眼睛保护大脑。
接下来的这部分,将会更加的让我们为大师的智慧折服。
第二级配置器引入了新的处理机制以应对内存碎片问题。不仅带来了回收难度的问题,并且同样带来了配置上的挑战。值得注意的是,在这种情况下(即系统需要划分大量资源用于管理其他资源),当块大小减小时(相当于将大块分割成更小的部分),会导致额外负载率上升。
(索求任何一块内存,都得有一些“回扣”要交给系统)
SGI第二级配置器解决了多少问题呢?那就看各位的理解到什么程度了。
SGI第二级配置器的做法是“:sub-allocation (层次架构):
每次分配一大块内存,并维护对应之自由链表(free-list)。
下次若再有相同大小的内存需求,则直接从free-lists中取出。
如果客端释放小额区块,就收回free-lists.
苍白的文字啊,看图:

清楚明了吧。
在内存管理方面,SGI配置器会自动将任何小块的内存需求量进位为2^3的倍数。这是因为整数字节的数量通常也是以2的幂次方的形式存在。
如果客端要求2个比特,就会自动分配到8比特。
并维护了16个free-list,图中已明确指出了。
如果我的图太难看,我在别的地方也找了一张:

free-list的节点结构真的是要惊叹的了:
看:
注:如果关于联合体把你困住了,我帮你解决了:工具包
union obj
{
union obj *free_list_link;
char client_data[1];
}
从表面看可能显得平淡无奇, 仔细审视一下那个union obj共出现了两次. 这样的做法有什么好处吗?
基于union机制,在第一个字段中分析,则可以认为该对象是一个指向的对象,并最终指向另一个对象。
从第二个字段来看,obj可以被看作一个指针,指向实际区块。
其优点在于无需为维护链表所需而产生的指针从而导致另一次内存浪费
秀吧,天秀!
好,接下来是第二级配置器的部分实现内容:
enum {__ALIGN = 8}; //小型区块的上调边界
enum {__MAX_BYTES = 128}; //小型区块的上限
enum {__NFREELISTS/ALIGN} //free-list个数
class __default_alloc_template{
private:
//将byte上调至8的倍数
static size_t ROUND_UP(size_t bytes){
return (((bytes)+__ALIGN-1) &~ (__ALIGN -1));
}
private:
//free-list的节点构造
private:
//16个free-list
static obj *volatile free_list[__NFREELISTS];
//根据区块大小,决定使用n号free-list。n从1开始算
static size_t FREELIST_INDEX(size_t bytes) {
return return (((bytes)+__ALIGN-1) / __ALIGN -1);
}
}
···
c.4空间配置函数allocate
文字叙述前面已经很详尽了,倒是代码零零散散,这里将代码串起来。
static void *alloc(size_t n)
{
obj * volatile my_free_list;
obj * result;
//一级
if( n > (size_t) __MAX_BYTES)
{
return (malloc_alloc::allocate(n));
}
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if(result == 0)
{
//没有可用free-list,准备重新填充
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result->free_list_link;
return (result);
}
c.5 空间释放函数deallocate
有配置自然要有相应的释放函数了。
文字叙述已经很详尽了,直接看代码吧。
static void deallocate(void *p,size_t n)
{
obj *q = (obj *)p;
obj *volatile *my_free_list;
if( n > (size_t) __MAX_BYTES)
{
malloc_alloc::deallocate(p,n);
return n;
}
//寻找对应的free list
my_free_list = free_list + FREELIST_INDEX(n);
//调整free_list,回收区块
q->free_list_link = *my_free_list;
*my_free_list = q;
}
c.6 重新填充free lists 函数refill
前面将这块放空。始终觉得看不过去。
在尝试为进程分配内存时, 发现内存中已用块不足以满足需求, 此时就需要使用refill机制从内存释放区获取额外的空间
void * __default_alloc_template</*参数不管它 />::refill(size_t n)
{
int nobjs = 20;
//调用chunk_alloc(),尝试取得nobjs个区块作为新节点
char *chunk = chunk_alloc(n,nobjs);
obj *volatile *my_free_list;
obj *result;
obj *current_obj,*next_obj;
int i;
if(1 == nobjs) //要是就剩一块儿了,先给调用者
return (chunk);
my_free_list = free_list + FREELIST_INDEX(n);
//睁大眼睛吧
//接下来准备在chunk空间中建立free list
result = (obj *)chunk; //先给调用者来一块
//接下来引导free list来拿地
*my_free_list = next_obj = (obj *)(chunk + n);
//然后将新拿到的地消化吸收
for(i = 1; ;i++) //从1开始,0给别人了
{
current_obj = next_obj;
next_obj = (obj *) ((char *)next_obj+n);
if(nobjs - 1 == i)
{
current_obj->free_list_link = 0;
break;
}
else
current_obj -> free_list_link = next_obj;
}
return (result);
}
c. 内存池的chunk_alloc()操作
从内存池中取空间给free list 使用,是chunk_alloc() 的工作。
(const char*)_defaultalloctemplate/忽略无关参数/::ChunkAlloc(size_t size, int& nobjs)
{
char * result;
size_t total_bytes = size *nobjs;
size_t bytes_left = end_free - start_free; //内存池还有多少水
if(bytes_left>=total_bytes)
{
result = start_free;
start_free += total_bytes;
return (result);
}
else if(bytes_left >= size) //不够总量,但是总归还是有一些存货的
{
nobjs = bytes_left/size;
total_bytes = size*nobjs;
result = start_free;
start_free += total_bytes;
return (result);
//能给多少多少给多少吧
}


该平台提供全面的学习资源包:既有 cater to 初学者的入门级学习材料(Zero Foundation),也有专为 3 年以上经验者设计的深入学习课程(Advanced Learning),覆盖了 C/C++ 开发所需 95%以上的知识点,并且系统性非常强!
因为文件数量较多的原因,在此处仅用于展示整个集合的概况。整个资源包包含以下几大核心模块:canonical面试题库、个人知识库、代码详解文档以及实践案例库。此外还附带课程规划表单和教学视频资源库,并会定期补充更多优质内容。
//内存池还有多少水
AI写代码
if(bytes_left>=total_bytes)
{
result = start_free;
start_free += total_bytes;
return (result);
}
else if(bytes_left >= size) //不够总量,但是总归还是有一些存货的
{
nobjs = bytes_left/size;
total_bytes = size*nobjs;
result = start_free;
start_free += total_bytes;
return (result);
//能给多少多少给多少吧
}
[外链图片转存中…(img-plOO6bBb-1715563144911)]
[外链图片转存中…(img-xVgAYzSB-1715563144912)]
该平台提供丰富的入门学习资源和专业课程,在C/C++开发领域涵盖了绝大多数知识点,并且系统性强
因为文件数量较多,在这里仅用于展示目录结构。整个集合包含以下内容:canonical interview questions(大厂面经)、lecture notes(学习笔记)、source code materials(源码讲义)、practical projects(实战项目)、course outlines or pathways(大纲路线)、video tutorials or walkthroughs(讲解视频)。后续计划定期更新以增加丰富度和及时性。
