Skip to content

Commit aafadcc

Browse files
committed
fix: 🐛 pool组件部分API加强完善,realloc待完整验证!!!
1 parent e1f7926 commit aafadcc

2 files changed

Lines changed: 162 additions & 78 deletions

File tree

core/fc_pool.c

Lines changed: 150 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,24 @@ size_t fc_pool_record_now(fc_pool_t *pool)
196196
}
197197

198198
//+********************************* 内存块状态管理及链式操作 **********************************/
199+
/**
200+
* @brief 获取当前(链式)内存块已使用大小
201+
*
202+
* @param ptr 当前内存块地址
203+
* @return size_t
204+
*/
205+
size_t fc_pool_used_size(void *ptr)
206+
{
207+
fc_assert(ptr != NULL);
208+
fc_pool_header_t *node = fc_pool_rewind_header(ptr); // 从ptr指向的内存块开始,返回内存块头部地址
209+
size_t used_size = 0;
210+
while (node)
211+
{
212+
used_size += node->used_size;
213+
node = node->next;
214+
}
215+
return used_size;
216+
}
199217

200218
/**
201219
* @brief 标记当前内存块已使用大小
@@ -676,7 +694,7 @@ void fc_pool_free(fc_pool_t *pool, void *ptr)
676694

677695
// 开始合并到空闲链表
678696
{
679-
after = NULL;
697+
// after = NULL;
680698
prev = NULL;
681699
prev_first = NULL;
682700
FC_ATOMIC_SCOPE
@@ -961,109 +979,158 @@ void *fc_pool_realloc(fc_pool_t *pool, void *ptr, size_t size)
961979
{
962980
need_count = (int32_t)(((size + sizeof(fc_pool_header_t) + node_size - 1) / node_size) - node->block_count); // 还需要多少个连续内存块
963981

964-
if (1 == need_count) // 只需要一个内存块
982+
if (0 == need_count) // 当前链上还有空闲内存仅仅修改标记大小
983+
{
984+
// 保持不变,仅仅修改标记大小
985+
fc_pool_mark_used(ptr, size); // 标记实际使用大小
986+
return ptr;
987+
}
988+
else if (need_count < 0) // 还要释放部分内存,正常使用比较少
965989
{
966-
node = (fc_pool_header_t *)((uint8_t *)node + node->block_count * node_size); // 直接定位到需要取出的内存块第一个节点位置
990+
node = (fc_pool_header_t *)((uint8_t *)node - (node->block_count + need_count) * node_size); // 定位到需要释放的内存块第一个节点位置
967991
{
968-
FC_ATOMIC_SCOPE
992+
node->next = NULL; // 释放的内存块下一个节点指向NULL
993+
node->link_flag = FC_POOL_TAG_END;
994+
node->block_count = (-need_count);
995+
node->used_size = node->block_count * node_size - sizeof(fc_pool_header_t);
996+
}
997+
ret_ptr = fc_pool_skip_header(node);
998+
fc_pool_free(pool, ret_ptr);
999+
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成
1000+
}
1001+
else if (pool->sort_free_enable)
1002+
{
1003+
if (1 == need_count) // 只需要一个内存块
1004+
{
1005+
node = (fc_pool_header_t *)((uint8_t *)node + node->block_count * node_size); // 直接定位到需要取出的内存块第一个节点位置
9691006
{
970-
// 遍历空闲链表看需要取出的内存块是否还在空闲链表中
971-
node_free = pool->list_free.next;
972-
node_prev = &(pool->list_free);
973-
while (node_free) // 最坏O(n)
1007+
FC_ATOMIC_SCOPE
9741008
{
975-
if ((size_t)node_free == (size_t)node) // 链式内存是按顺序排列的,如果这块内存还未使用必定是一块链的起始
1009+
// 遍历空闲链表看需要取出的内存块是否还在空闲链表中
1010+
node_free = pool->list_free.next;
1011+
node_prev = &(pool->list_free);
1012+
while (node_free) // 最坏O(n)
9761013
{
977-
// 找到这块内存了
978-
node_prev->next = node_free->next; // 从空闲链表中移除
979-
980-
if (node_free->linear_last != node_free) // 非自旋节点,证明下一个节点跟这个节点是连续的(一定存在下一个节点)
1014+
if ((size_t)node_free == (size_t)node) // 链式内存是按顺序排列的,如果这块内存还未使用必定是一块链的起始
9811015
{
982-
node_free->next->linear_last = node_free->linear_last; // 使下一个节点指向连续内存块的最后一个节点
1016+
// 找到这块内存了
1017+
node_prev->next = node_free->next; // 从空闲链表中移除
1018+
if (node_free->linear_last != node_free) // 非自旋节点,证明下一个节点跟这个节点是连续的(一定存在下一个节点)
1019+
{
1020+
node_free->next->linear_last = node_free->linear_last; // 使下一个节点指向连续内存块的最后一个节点
1021+
}
1022+
pool->list_free.record_now -= need_count;
1023+
pool->record_min = MIN(pool->record_min, pool->list_free.record_now);
1024+
node->block_count += need_count;
1025+
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成,不能ATOMIC域内直接return
1026+
break;
1027+
}
1028+
node_prev = node_free->linear_last;
1029+
node_free = node_free->linear_last->next;
1030+
if ((size_t)node_free > (size_t)node) // 遍历到需要内存后面了证明需要分配的内存不再空闲链表中
1031+
{
1032+
break;
9831033
}
984-
985-
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成,不能ATOMIC域内直接return
986-
break;
9871034
}
988-
989-
node_prev = node_free->linear_last;
990-
node_free = node_free->linear_last->next;
991-
992-
if ((size_t)node_free > (size_t)node) // 遍历到需要内存后面了证明需要分配的内存不再空闲链表中
1035+
}
1036+
}
1037+
}
1038+
else if (need_count > 1) // 需要两个及以上连续内存块
1039+
{
1040+
node = (fc_pool_header_t *)((uint8_t *)node + node->block_count * node_size); // 直接定位到需要取出的内存块第一个节点位置
1041+
node_end = (fc_pool_header_t *)((uint8_t *)node + (need_count - 1) * node_size); // 得到需要分配出去的最后一个节点位置
1042+
{
1043+
FC_ATOMIC_SCOPE
1044+
{
1045+
// 遍历空闲链表看需要取出的内存块是否还在空闲链表中
1046+
node_free = pool->list_free.next;
1047+
node_prev = &(pool->list_free);
1048+
while (node_free) // 最坏O(n)
9931049
{
994-
break;
1050+
if ((size_t)node_free == (size_t)node && (size_t)(node_free->linear_last) >= (size_t)node_end) // 链式内存是按顺序排列的,如果这块内存还未使用必定是一块链的起始,从这块内存开始到node_end都是空闲的
1051+
{
1052+
// 找到这块内存了
1053+
node_prev->next = node_end->next; // 从空闲链表中移除
1054+
if (node_free->linear_last != node_end) // 起始节点指向的最后一个连续节点不是分配出去的最后一个节点
1055+
{
1056+
node_end->next->linear_last = node_free->linear_last; // 使下一个节点指向连续内存块的最后一个节点
1057+
}
1058+
pool->list_free.record_now -= need_count;
1059+
pool->record_min = MIN(pool->record_min, pool->list_free.record_now);
1060+
node->block_count += need_count;
1061+
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成,不能ATOMIC域内直接return
1062+
break;
1063+
}
1064+
node_prev = node_free->linear_last;
1065+
node_free = node_free->linear_last->next;
1066+
if ((size_t)node_free > (size_t)node) // 遍历到需要内存后面了证明需要分配的内存不再空闲链表中
1067+
{
1068+
break;
1069+
}
9951070
}
9961071
}
9971072
}
9981073
}
9991074
}
1000-
else if (need_count > 1) // 需要两个及以上连续内存块
1075+
else
10011076
{
1002-
node = (fc_pool_header_t *)((uint8_t *)node + node->block_count * node_size); // 直接定位到需要取出的内存块第一个节点位置
1003-
node_end = (fc_pool_header_t *)((uint8_t *)node + (need_count - 1) * node_size); // 得到需要分配出去的最后一个节点位置
1004-
1077+
// need_count >= 1,需要判断连续的内存块是否被使用,内存块未排序
1078+
size_t count = 0;
1079+
fc_pool_header_t *node_part_front = &(pool->list_free); // 需要提取出的内存块的前一个节点
1080+
node_prev = (fc_pool_header_t *)((uint8_t *)node + node->block_count * node_size); // 直接定位到需要取出的内存块第一个节点位置
1081+
node_end = (fc_pool_header_t *)((uint8_t *)node + (need_count - 1) * node_size); // 得到需要分配出去的最后一个节点位置
1082+
FC_ATOMIC_SCOPE
10051083
{
1006-
FC_ATOMIC_SCOPE
1084+
node_free = pool->list_free.next;
1085+
while (node_free)
10071086
{
1008-
// 遍历空闲链表看需要取出的内存块是否还在空闲链表中
1009-
node_free = pool->list_free.next;
1010-
node_prev = &(pool->list_free);
1011-
while (node_free) // 最坏O(n)
1087+
if ((size_t)node_free >= (size_t)node_prev && (size_t)node_free <= (size_t)node_end)
10121088
{
1013-
if ((size_t)node_free == (size_t)node && (size_t)(node_free->linear_last) >= (size_t)node_end) // 链式内存是按顺序排列的,如果这块内存还未使用必定是一块链的起始,从这块内存开始到node_end都是空闲的
1089+
count++;
1090+
if (count >= need_count)
10141091
{
1015-
// 找到这块内存了
1016-
node_prev->next = node_end->next; // 从空闲链表中移除
1017-
1018-
if (node_free->linear_last != node_end) // 起始节点指向的最后一个连续节点不是分配出去的最后一个节点
1092+
break;
1093+
}
1094+
}
1095+
node_free = node_free->next;
1096+
}
1097+
if (count >= need_count)
1098+
{
1099+
node_free = pool->list_free.next; // 从头开始,一边遍历一边提取
1100+
// 从链中提取出需要的内存块
1101+
while (node_free)
1102+
{
1103+
if ((size_t)node_free >= (size_t)node_prev && (size_t)node_free <= (size_t)node_end)
1104+
{
1105+
node_part_front->next = node_free->next; // 从链中移除
1106+
if ((size_t)(node_free->linear_last) != (size_t)node_free) // 非自旋节点,证明下一个节点跟这个节点是连续的(一定存在下一个节点),无需判断(NULL != node->next)
10191107
{
1020-
node_end->next->linear_last = node_free->linear_last; // 使下一个节点指向连续内存块的最后一个节点
1108+
node_free->next->linear_last = node_free->linear_last; // 使下一个节点指向连续内存块的最后一个节点
1109+
}
1110+
count--;
1111+
if (count <= 0)
1112+
{
1113+
pool->list_free.record_now -= need_count;
1114+
pool->record_min = MIN(pool->record_min, pool->list_free.record_now);
1115+
node->block_count += need_count;
1116+
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成,不能ATOMIC域内直接return
1117+
break;
10211118
}
1022-
1023-
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成,不能ATOMIC域内直接return
1024-
break;
10251119
}
1026-
1027-
node_prev = node_free->linear_last;
1028-
node_free = node_free->linear_last->next;
1029-
1030-
if ((size_t)node_free > (size_t)node) // 遍历到需要内存后面了证明需要分配的内存不再空闲链表中
1120+
else
10311121
{
1032-
break;
1122+
node_part_front = node_free;
10331123
}
1124+
node_free = node_free->next;
10341125
}
10351126
}
10361127
}
10371128
}
1038-
else if (0 == need_count) // 当前链上还有空闲内存仅仅修改标记大小
1039-
{
1040-
// 保持不变,仅仅修改标记大小
1041-
fc_pool_mark_used(ptr, size); // 标记实际使用大小
1042-
return ptr;
1043-
}
1044-
else if (need_count < 0) // 还要释放部分内存,正常使用比较少
1045-
{
1046-
node = (fc_pool_header_t *)((uint8_t *)node - (node->block_count + need_count) * node_size); // 定位到需要释放的内存块第一个节点位置
1047-
ret_ptr = fc_pool_skip_header(node);
1048-
fc_pool_free(pool, ret_ptr);
1049-
ret_ptr = ptr; // 赋值用于下面判断realloc是否完成
1050-
}
10511129
}
1052-
10531130
if (ret_ptr) // 执行到这儿且不为空证明正常完成了realloc操作(基于原始内存)
10541131
{
10551132
fc_pool_mark_used(ret_ptr, size); // 标记实际使用大小
10561133
}
1057-
else
1058-
{
1059-
ret_ptr = fc_pool_malloc(pool, size); // 重新分配内存
1060-
if (ret_ptr) // 分配成功
1061-
{
1062-
memcpy(ret_ptr, ptr, size); // 复制内存
1063-
fc_pool_free(pool, ptr); // 释放旧内存
1064-
}
1065-
}
1066-
10671134
return ret_ptr;
10681135
}
10691136

@@ -1223,6 +1290,18 @@ void *fc_header_fifo_pop(fc_pool_header_t *header)
12231290
return (void *)(node ? (uint8_t *)node + sizeof(fc_pool_header_t) : NULL);
12241291
}
12251292

1293+
/**
1294+
* @brief 从fifo used链表头部查看一条链式非连续内存块,O(1)复杂度
1295+
*
1296+
* @param header
1297+
* @return void*
1298+
*/
1299+
void *fc_header_fifo_peek(fc_pool_header_t *header)
1300+
{
1301+
fc_assert(header != NULL);
1302+
return (void *)(header->next ? (uint8_t *)header->next + sizeof(fc_pool_header_t) : NULL);
1303+
}
1304+
12261305
#if 0
12271306
/**
12281307
* @brief 检查内存池是否正常

core/fc_pool.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,12 @@ extern "C"
112112
size_t fc_pool_record_now(fc_pool_t *pool); // 内存池当前记录(剩余块)
113113

114114
//+********************************* 内存块状态管理及链式操作 **********************************/
115-
bool fc_pool_mark_used(void *ptr, size_t used_size); // 标记当前内存块已使用大小,ptr当前内存块地址
116-
void fc_pool_end(void *ptr); // 给指定链式内存块的最后一块做标记,创建的时候默认已经标记
117-
void fc_pool_link(void *front, void *back); // 将front和back链接起来,非连续内存块
118-
bool fc_pool_linear_check(void *ptr); // 检查ptr是否为连续内存块,如果是返回true,否则返回false
119-
void fc_pool_walk(void *ptr, fc_pool_walker_t walker, void *user); // 遍历链式非连续内存块
115+
size_t fc_pool_used_size(void *ptr); // 获取当前(链式)内存块已使用大小,ptr当前内存块地址
116+
bool fc_pool_mark_used(void *ptr, size_t used_size); // 标记当前内存块已使用大小,ptr当前内存块地址
117+
void fc_pool_end(void *ptr); // 给指定链式内存块的最后一块做标记,创建的时候默认已经标记
118+
void fc_pool_link(void *front, void *back); // 将front和back链接起来,非连续内存块
119+
bool fc_pool_linear_check(void *ptr); // 检查ptr是否为连续内存块,如果是返回true,否则返回false
120+
void fc_pool_walk(void *ptr, fc_pool_walker_t walker, void *user); // 遍历链式非连续内存块
120121

121122
void fc_pool_fifo_walk(fc_pool_t *pool, fc_pool_walker_t walker, void *user); // 遍历整个fifo used队列链表,遍历后释放内存
122123
bool fc_pool_merge(fc_pool_t *pool, void *front, void *back); // 将front和back合并,将back内存拼接到front后面,返回是否成功合并
@@ -126,16 +127,17 @@ extern "C"
126127
void *fc_pool_alloc(fc_pool_t *pool, size_t *size); // 区别于malloc,传入size的指针分配成功将设置为实际分配(用户可用)的大小,返回可用的内存地址,固定O(1)复杂度
127128
// sort_free_enable == false时,free复杂度为O1,true的情况下以下free复杂度为O(n)
128129
void fc_pool_free(fc_pool_t *pool, void *ptr); // 如果是链式非连续内存块,会将整个链式内存块释放掉,O(n)复杂度,n为链式内存块的块数
129-
// sort_free_enable == false时,realloc大小不超过1块时有概率成功,否则绝大概率失败? // TODO:feature:可优化为超过1块时仍有较大概率成功,且效率O(n)
130+
// realloc在任何情况下均为O(n)复杂度
130131
void *fc_pool_realloc(fc_pool_t *pool, void *ptr, size_t size); // 等效realloc,最坏O(n)复杂度
131-
// sort_free_enable == false时,以下API分配超过1块时绝大概率失败,反之O(1)复杂度
132+
// sort_free_enable == false时,以下API分配超过1块时很大概率失败,不超过1块则O(1)复杂度
132133
void *fc_pool_malloc(fc_pool_t *pool, size_t size); // 等效malloc,尝试分配size字节的连续内存,如果失败则返回NULL,最坏O(n)复杂度
133134
void *fc_pool_calloc(fc_pool_t *pool, size_t count, size_t size); // 等效calloc,最坏O(n)复杂度
134135

135136
//+********************************* fc_pool_header_t对象当fifo使用 **********************************/
136137
bool fc_header_fifo_empty(fc_pool_header_t *header); // fifo是否为空
137138
void fc_header_fifo_push(fc_pool_header_t *header, void *head_ptr); // 将整个链式非连续内存块添加到fifo
138139
void *fc_header_fifo_pop(fc_pool_header_t *header); // 从fifo中弹出一块链式非连续内存块
140+
void *fc_header_fifo_peek(fc_pool_header_t *header); // 从fifo中查看一块链式非连续内存块,不弹出
139141

140142
#define fc_pool_fifo_empty(pool) \
141143
fc_header_fifo_empty(&((pool)->fifo_used))
@@ -146,6 +148,9 @@ extern "C"
146148
#define fc_pool_fifo_pop(pool) \
147149
fc_header_fifo_pop(&((pool)->fifo_used))
148150

151+
#define fc_pool_fifo_peek(pool) \
152+
fc_header_fifo_peek(&((pool)->fifo_used))
153+
149154
//+********************************* 其他 **********************************/
150155
// bool fc_pool_check(fc_pool_t *pool); // 检查内存池是否正常
151156
size_t fc_pool_max_linear_count(fc_pool_t *pool); // 内存池最大连续内存块数

0 commit comments

Comments
 (0)