mysql层的内存分配
参考 http://www.cnblogs.com/justfortaste/p/3198406.html
http://m.blog.csdn.net/blog/IT_PCode/17007833
http://blog.chinaunix.net/uid-28364803-id-3419777.html
http://blog.chinaunix.net/uid-26896862-id-3412033.html
mysql数据库分mysql层和存储引擎层,每个层都有各自的分配内存方法
mysql层分配内存方法比较简单
当一个请求过来后,使用一个线程为其服务,mysql层为它分配内存
mysql层mem_root
typedef struct st_used_mem { /* struct for once_alloc (block) */ struct st_used_mem *next; /* Next block in use */ unsigned int left; /* memory left in block */ unsigned int size; /* size of block */ } USED_MEM; typedef struct st_mem_root { USED_MEM *free; /* blocks with free memory in it */ USED_MEM *used; /* blocks almost without free memory */ USED_MEM *pre_alloc; /* preallocated block */ /* if block have less memory it will be put in 'used' list */ size_t min_malloc; size_t block_size; /* initial block size */ unsigned int block_num; /* allocated blocks counter */ /* first free block in queue test counter (if it exceed MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) */ unsigned int first_block_usage; void (*error_handler)(void); } MEM_ROOT;
mysql内存池 mysql内部使用的内存管理程序,可以实现多次申请内存块, 中途任何时刻失败, 或者下次使用前释放内存, 无需再关心每次申请和释放了哪些内存. 工作原理: 初始化定义每次分配的最小内存块大小M,如果申请一次内存, 大小为X, X大于M, 就分配一块X的内存, 加入到管理链表中.如果小于的话, 看之前剩余的还够不够, 如果足够的话, 返回之前多余的内存地址.如果不够,则申请这么大的内存, 也计入链表中。 释放是一次性的,也可以不释放内存,而是标记已经使用的内存为“未使用”,下次同样的应用可以继续使用。 创建内存池 /* Initialize memory root SYNOPSIS init_alloc_root() mem_root - memory root to initialize block_size - size of chunks (blocks) used for memory allocation (It is external size of chunk i.e. it should include memory required for internal structures, thus it should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE) pre_alloc_size - if non-0, then size of block that should be pre-allocated during memory root initialization. DESCRIPTION This function prepares memory root for further use, sets initial size of chunk for memory allocation and pre-allocates first block if specified. Altough error can happen during execution of this function if pre_alloc_size is non-0 it won't be reported. Instead it will be reported as error in first alloc_root() on this memory root. */ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size __attribute__((unused))) { DBUG_ENTER("init_alloc_root"); mem_root->free = mem_root->used = mem_root->pre_alloc = 0; mem_root->min_malloc = 32; mem_root->block_size = block_size - ALLOC_ROOT_MIN_BLOCK_SIZE; mem_root->error_handler = 0; mem_root->block_num = 4; /* We shift this with >>2 */ mem_root->first_block_usage = 0; if (pre_alloc_size) { if ((mem_root->free = mem_root->pre_alloc = (USED_MEM*) my_malloc( pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM)), MYF(0)))) { mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM)); mem_root->free->left= pre_alloc_size; mem_root->free->next= 0; } } DBUG_VOID_RETURN; } 申请内存 gptr alloc_root(MEM_ROOT *mem_root, unsigned int Size) { uint get_size, block_size; gptr point; reg1 USED_MEM *next = 0; reg2 USED_MEM **prev; DBUG_ENTER("alloc_root");DBUG_ASSERT(alloc_root_inited(mem_root)); Size = ALIGN_SIZE(Size); if ((*(prev = &mem_root->free)) != NULL) { if ((*prev)->left < Size && mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP && (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP) { next = *prev; *prev = next->next; /* Remove block from list */ next->next = mem_root->used; mem_root->used = next; mem_root->first_block_usage = 0; } for (next = *prev; next && next->left < Size; next = next->next) prev = &next->next; } if (!next) { /* Time to alloc new block */ block_size = mem_root->block_size * (mem_root->block_num >> 2); get_size = Size + ALIGN_SIZE(sizeof(USED_MEM)); get_size = max(get_size, block_size); if (!(next = (USED_MEM*) my_malloc(get_size, MYF(MY_WME)))) { if (mem_root->error_handler) (*mem_root->error_handler)(); return ((gptr) 0); /* purecov: inspected */ } mem_root->block_num++; next->next = *prev; next->size = get_size; next->left = get_size - ALIGN_SIZE(sizeof(USED_MEM)); *prev = next; } point = (gptr) ((char*) next + (next->size - next->left)); /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/ if ((next->left -= Size) < mem_root->min_malloc) { /* Full block */ *prev = next->next; /* Remove block from list */ next->next = mem_root->used; mem_root->used = next; mem_root->first_block_usage = 0; }DBUG_RETURN(point); } 释放内存 /* Deallocate everything used by alloc_root or just move used blocks to free list if called with MY_USED_TO_FREE SYNOPSIS free_root() root Memory root MyFlags Flags for what should be freed: MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free MY_KEEP_PREALLOC If this is not set, then free also the preallocated block NOTES One can call this function either with root block initialised with init_alloc_root() or with a bzero()-ed block. It's also safe to call this multiple times with the same mem_root. */ void free_root(MEM_ROOT *root, myf MyFlags) { reg1 USED_MEM *next, *old; DBUG_ENTER("free_root"); if (!root) /* QQ: Should be deleted */ DBUG_VOID_RETURN; /* purecov: inspected */ if (MyFlags & MY_MARK_BLOCKS_FREE) { mark_blocks_free(root); DBUG_VOID_RETURN; } if (!(MyFlags & MY_KEEP_PREALLOC)) root->pre_alloc = 0; for (next = root->used; next;) { old = next; next = next->next; if (old != root->pre_alloc) my_free((gptr) old, MYF(0)); } for (next = root->free; next;) { old = next; next = next->next; if (old != root->pre_alloc) my_free((gptr) old, MYF(0)); } root->used = root->free = 0; if (root->pre_alloc) { root->free = root->pre_alloc; root->free->left = root->pre_alloc->size - ALIGN_SIZE(sizeof(USED_MEM)); TRASH_MEM(root->pre_alloc); root->free->next = 0; } root->block_num = 4; root->first_block_usage = 0; DBUG_VOID_RETURN; } 内存池使用实例 void test_myalloc() { MEM_ROOT root; char *str; init_alloc_root(&root, 1 << 12, 1 << 10); str = (char *) alloc_root(&root, 1024 * sizeof(double)); if (NULL == str) printf("cannot get memory for alloc root for str\n"); strcpy(str, "hello\n"); puts(str); //mark free, can be used again free_root(&root, MY_MARK_BLOCKS_FREE); //free, can not be used free_root(&root, 0); }
void my_free(void *ptr) { DBUG_ENTER("my_free"); DBUG_PRINT("my",("ptr: %p", ptr)); free(ptr); DBUG_VOID_RETURN; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
· SQL Server统计信息更新会被阻塞或引起会话阻塞吗?
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目