文章目录
- 内存模型:
- 流程图
- 内存对齐
- code
内存模型:
流程图
内存对齐
对齐计算
要分配一个以指定大小对齐的内存,可以使用如下公式:
假设要分配大小为n,对齐方式为x,那么 size=(n+(x-1)) & (~(x-1))。
举个例子:
n=17,x=4。即申请大小为17,对齐为4。则计算出对齐后的大小应该为
(17+4-1)&(~(4-1))=20;
code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define MP_ALIGNMENT 32
#define MP_PAGE_SIZE 4096
#define MP_MAX_ALLOC_FROM_POOL (MP_PAGE_SIZE-1)
// 对齐
#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))
typedef struct mp_large_s {
struct mp_large_s *next;
void *alloc;
}mp_large_t;
typedef struct mp_node_s {
unsigned char *last; // last之前为已使用的内存
unsigned char *end; // last到end之间为可分配内存
struct mp_node_s *next;
size_t failed;
}mp_node_t;
typedef struct mp_pool_s {
size_t max;
mp_node_t* current;
mp_large_t* large;
mp_node_t head[0];
}mp_pool_t;
mp_pool_t *mp_create_pool(size_t size)
{
mp_pool_t *p;
// malloc无法分配超过4k的内存,size + sizeof(mp_pool_t) + sizeof(mp_node_s)保证有size大小可用
int ret = posix_memalign((void*)&p, MP_ALIGNMENT, size + sizeof(mp_pool_t) + sizeof(mp_node_t));
if (ret)
return NULL;
p->max = size;
p->current = p->head;
p->large = NULL;
//(unsigned char*)(p + 1)
// (unsigned char*)p + sizeof(mp_pool_t)
p->head->last = (unsigned char*)p + sizeof(mp_pool_t)+sizeof(mp_node_t);
p->head->end = p->head->last + size;
p->head->failed = 0;
return p;
}
void mp_destory_pool(mp_pool_t *pool)
{
mp_node_t *h, *n;
mp_large_t *l;
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
free(l->alloc);
}
}
h = pool->head->next;
while (h) {
n = h->next;
free(h);
h = n;
}
free(pool);
}
void *mp_alloc_small(mp_pool_t *pool, size_t size)
{
unsigned char *m;
struct mp_node_s *h = pool->head;
size_t psize = (size_t)(h->end - (unsigned char *)h);
int ret = posix_memalign((void*)&m, MP_ALIGNMENT, psize);
if (ret)
return NULL;
mp_node_t *p, *new_node, *current;
new_node = (mp_node_t *)m;
new_node->next = NULL;
new_node->end = m + psize;
new_node->failed = 0;
m += sizeof(mp_node_t);
m = mp_align_ptr(m, MP_ALIGNMENT);
new_node->last += size;
current = pool->current;
for (p = current; p->next; p = p->next)
{
// 如存在多次分配失败,current不再指向此node
if (p->failed++ > 4)
{
current = p->next;
}
}
p->next = new_node;
pool->current = current ? current : new_node;
return m;
}
static void *mp_alloc_large(mp_pool_t *pool, size_t size)
{
void *p = NULL;
int ret = posix_memalign((void*)&p, MP_ALIGNMENT, size);
if (ret)
return NULL;
mp_large_t *large;
// 查找是否有已经释放的large,在large list里面找到一个 null的节点
size_t n = 0;
for (large = pool->large; large; large = large->next)
{
if (large->alloc == NULL)
{
large->alloc = p;
return p;
}
// 避免遍历链条太长
if (n++ > 3)
break;
}
// 大内存块的头作为小块保存在small中
large = mp_alloc_small(pool, sizeof(mp_large_t));
// 头插法
large->alloc = p;
large->next = pool->large;
pool->large = large;
}
void *mp_malloc(mp_pool_t *pool, size_t size)
{
if (size > pool->max)
return mp_alloc_large(pool, size);
mp_node_t *p = pool->current;
while (p)
{
if (p->end - p->last < size)
{
p = p->next;
continue;
}
unsigned char *m = mp_align_ptr(p->last, MP_ALIGNMENT);
p->last = m + size;
return m;
}
return mp_alloc_small(pool, size);
}
void *mp_calloc(mp_pool_t *pool, size_t size)
{
void *p = mp_malloc(pool, size);
if (p) {
memset(p, 0, size);
}
return p;
}
void mp_free(mp_pool_t *pool, void *p)
{
mp_large_t *l;
for (l = pool->large; l; l = l->next)
{
if (p == l->alloc)
{
free(l->alloc);
l->alloc = NULL;
return;
}
}
}
void mp_reset_pool(mp_pool_t *pool)
{
mp_node_t *h;
mp_large_t *l;
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
free(l->alloc);
}
}
pool->large = NULL;
for (h = pool->head; h; h = h->next) {
h->last = (unsigned char *)h + sizeof(mp_node_t);
}
}
/******************* TEST *********************/
int main(int argc, char *argv[]) {
int size = 1 << 12;
mp_pool_t *p = mp_create_pool(size);
int i = 0;
for (i = 0; i < 10; i++) {
void *mp = mp_malloc(p, 512);
// mp_free(mp);
}
printf("mp_align(123, 32): %d, mp_align(17, 32): %d\n", mp_align(24, 32), mp_align(17, 32));
int j = 0;
for (i = 0; i < 5; i++) {
char *pp = mp_calloc(p, 32);
for (j = 0; j < 32; j++) {
if (pp[j]) {
printf("calloc wrong\n");
}
printf("calloc success\n");
}
}
//printf("mp_reset_pool\n");
for (i = 0; i < 5; i++) {
void *l = mp_malloc(p, 8192);
mp_free(p, l);
}
mp_reset_pool(p);
//printf("mp_destory_pool\n");
for (i = 0; i < 58; i++) {
mp_malloc(p, 256);
}
mp_destory_pool(p);
return 0;
}
参考:
https://blog.csdn.net/Long_xu/article/details/126887578