malloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. #include <libc/stdlib.h>
  2. #include <libsystem/syscall.h>
  3. #include <libc/stddef.h>
  4. #include <libc/unistd.h>
  5. #include <libc/errno.h>
  6. #include <libc/stdio.h>
  7. /**
  8. * @brief 显式链表的结点
  9. *
  10. */
  11. typedef struct malloc_mem_chunk_t
  12. {
  13. uint64_t start_addr; // 整个块所在内存区域的起始地址(包括header)
  14. uint64_t length; // 整个块所占用的内存区域的大小
  15. struct malloc_mem_chunk_t *prev; // 上一个结点的指针
  16. struct malloc_mem_chunk_t *next; // 下一个结点的指针
  17. } malloc_mem_chunk_t;
  18. static uint64_t brk_base_addr = 0; // 堆区域的内存基地址
  19. static uint64_t brk_max_addr = 0; // 堆区域的内存最大地址
  20. static uint64_t brk_managed_addr = 0; // 堆区域已经被管理的地址
  21. // 空闲链表
  22. // 按start_addr升序排序
  23. static malloc_mem_chunk_t *malloc_free_list = NULL;
  24. // 已分配链表
  25. // 使用LIFO策略。基于假设:程序运行早期分配的内存会被最晚释放
  26. static malloc_mem_chunk_t *malloc_allocated_list = NULL;
  27. /**
  28. * @brief 获取一块堆内存(不尝试扩大堆内存)
  29. *
  30. * @param size
  31. * @return void* 内存的地址指针,获取失败时返回-ENOMEM
  32. */
  33. static void *malloc_no_enlarge(ssize_t size);
  34. /**
  35. * @brief 将块插入空闲链表
  36. *
  37. * @param ck 待插入的块
  38. */
  39. static void malloc_insert_free_list(malloc_mem_chunk_t *ck);
  40. /**
  41. * @brief 在链表中检索符合要求的空闲块(best fit)
  42. *
  43. * @param size 块的大小
  44. * @return malloc_mem_chunk_t*
  45. */
  46. static malloc_mem_chunk_t *malloc_query_free_chunk_bf(uint64_t size)
  47. {
  48. // 在满足best fit的前提下,尽可能的使分配的内存在低地址
  49. // 使得总的堆内存可以更快被释放
  50. if (malloc_free_list == NULL)
  51. {
  52. printf("free list is none.\n");
  53. return NULL;
  54. }
  55. malloc_mem_chunk_t *ptr = malloc_free_list;
  56. malloc_mem_chunk_t *best = NULL;
  57. printf("query size=%d", size);
  58. while (ptr != NULL)
  59. {
  60. printf("ptr->length=%#010lx\n", ptr->length);
  61. if (ptr->length == size)
  62. {
  63. best = ptr;
  64. break;
  65. }
  66. if (ptr->length > size)
  67. {
  68. printf("676767\n");
  69. if (best == NULL)
  70. best = ptr;
  71. else if (best->length > ptr->length)
  72. best = ptr;
  73. printf("6rdf\n");
  74. }
  75. printf("ptr->next=%#018lx\n", ptr->next);
  76. ptr = ptr->next;
  77. }
  78. printf("return best=%#018lx\n", (uint64_t)best);
  79. return best;
  80. }
  81. /**
  82. * @brief 在链表中检索符合要求的空闲块(first fit)
  83. *
  84. * @param size
  85. * @return malloc_mem_chunk_t*
  86. */
  87. static malloc_mem_chunk_t *malloc_query_free_chunk_ff(uint64_t size)
  88. {
  89. if (malloc_free_list == NULL)
  90. return NULL;
  91. malloc_mem_chunk_t *ptr = malloc_free_list;
  92. while (ptr)
  93. {
  94. if (ptr->length >= size)
  95. {
  96. return ptr;
  97. }
  98. ptr = ptr->next;
  99. }
  100. return NULL;
  101. }
  102. /**
  103. * @brief 扩容malloc管理的内存区域
  104. *
  105. * @param size 扩大的内存大小
  106. */
  107. static int malloc_enlarge(int32_t size)
  108. {
  109. if (brk_base_addr == 0) // 第一次调用,需要初始化
  110. {
  111. brk_base_addr = brk(-1);
  112. printf("brk_base_addr=%#018lx\n", brk_base_addr);
  113. brk_managed_addr = brk_base_addr;
  114. brk_max_addr = brk(-2);
  115. }
  116. int64_t tmp = brk_managed_addr + size - brk_max_addr;
  117. if (tmp > 0) // 现有堆空间不足
  118. {
  119. if (sbrk(tmp) != (void *)(-1))
  120. brk_max_addr = brk((-2));
  121. else
  122. {
  123. put_string("malloc_enlarge(): no_mem\n", COLOR_YELLOW, COLOR_BLACK);
  124. return -ENOMEM;
  125. }
  126. }
  127. // 扩展管理的堆空间
  128. // 在新分配的内存的底部放置header
  129. malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)brk_managed_addr;
  130. new_ck->start_addr = (uint64_t)new_ck;
  131. new_ck->length = brk_max_addr - brk_managed_addr;
  132. printf("new_ck->start_addr=%#018lx\tbrk_max_addr=%#018lx\tbrk_managed_addr=%#018lx\n", new_ck->start_addr, brk_max_addr, brk_managed_addr);
  133. new_ck->prev = new_ck->next = NULL;
  134. brk_managed_addr = brk_max_addr;
  135. malloc_insert_free_list(new_ck);
  136. return 0;
  137. }
  138. /**
  139. * @brief 合并空闲块
  140. *
  141. */
  142. static void malloc_merge_free_chunk()
  143. {
  144. if (malloc_free_list == NULL)
  145. return;
  146. malloc_mem_chunk_t *ptr = malloc_free_list->next;
  147. while (ptr)
  148. {
  149. // 内存块连续
  150. if (ptr->prev->start_addr + ptr->prev->length == ptr->start_addr)
  151. {
  152. // 将ptr与前面的空闲块合并
  153. ptr->prev->length += ptr->length;
  154. ptr->prev->next = ptr->next;
  155. // 由于内存组成结构的原因,不需要free掉header
  156. ptr = ptr->prev;
  157. }
  158. ptr = ptr->next;
  159. }
  160. }
  161. /**
  162. * @brief 将块插入空闲链表
  163. *
  164. * @param ck 待插入的块
  165. */
  166. static void malloc_insert_free_list(malloc_mem_chunk_t *ck)
  167. {
  168. if (malloc_free_list == NULL) // 空闲链表为空
  169. {
  170. malloc_free_list = ck;
  171. ck->prev = ck->next = NULL;
  172. return;
  173. }
  174. else
  175. {
  176. uint64_t ck_end = ck->start_addr + ck->length;
  177. malloc_mem_chunk_t *ptr = malloc_free_list;
  178. while (ptr)
  179. {
  180. if (ptr->start_addr < ck->start_addr)
  181. {
  182. if (ptr->next == NULL) // 当前是最后一个项
  183. {
  184. ptr->next = ck;
  185. ck->next = NULL;
  186. ck->prev = ptr;
  187. break;
  188. }
  189. else if (ptr->next->start_addr > ck->start_addr)
  190. {
  191. ck->prev = ptr;
  192. ck->next = ptr->next;
  193. ck->prev->next = ck;
  194. ck->next->prev = ck;
  195. break;
  196. }
  197. }
  198. else // 在ptr之前插入
  199. {
  200. if (ptr->prev == NULL) // 是第一个项
  201. {
  202. malloc_free_list = ck;
  203. ck->prev = NULL;
  204. ck->next = ptr;
  205. ptr->prev = ck;
  206. break;
  207. }
  208. else
  209. {
  210. ck->prev = ptr->prev;
  211. ck->next = ptr;
  212. ck->prev->next = ck;
  213. ptr->prev = ck;
  214. break;
  215. }
  216. }
  217. ptr = ptr->next;
  218. }
  219. }
  220. }
  221. /**
  222. * @brief 获取一块堆内存(不尝试扩大堆内存)
  223. *
  224. * @param size
  225. * @return void* 内存的地址指针,获取失败时返回-ENOMEM
  226. */
  227. static void *malloc_no_enlarge(ssize_t size)
  228. {
  229. // 加上header的大小
  230. size += sizeof(malloc_mem_chunk_t);
  231. // 采用best fit
  232. malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
  233. if (ck == NULL) // 没有空闲块
  234. {
  235. // 尝试合并空闲块
  236. malloc_merge_free_chunk();
  237. ck = malloc_query_free_chunk_bf(size);
  238. // 找到了合适的块
  239. if (ck)
  240. goto found;
  241. else
  242. return -ENOMEM; // 内存不足
  243. }
  244. found:;
  245. // 分配空闲块
  246. // 从空闲链表取出
  247. if (ck->prev == NULL) // 当前是链表的第一个块
  248. {
  249. malloc_free_list = ck->next;
  250. }
  251. else
  252. ck->prev->next = ck->next;
  253. if (ck->next != NULL) // 当前不是最后一个块
  254. ck->next->prev = ck->prev;
  255. // 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
  256. if (ck->length - size > sizeof(malloc_mem_chunk_t))
  257. {
  258. printf("new_ck = %#018lx\n", ((uint64_t)ck) + size);
  259. malloc_mem_chunk_t *new_ck = ((uint64_t)ck) + size;
  260. new_ck->length = ck->length - size;
  261. new_ck->start_addr = (uint64_t)new_ck;
  262. new_ck->prev = new_ck->next = NULL;
  263. ck->length = size;
  264. malloc_insert_free_list(new_ck);
  265. }
  266. printf("12121212\n");
  267. // 插入到已分配链表
  268. // 直接插入到链表头,符合LIFO
  269. ck->prev = NULL;
  270. if (malloc_allocated_list) // 已分配链表不为空
  271. {
  272. malloc_allocated_list->prev = ck;
  273. ck->next = malloc_allocated_list;
  274. malloc_allocated_list = ck;
  275. }
  276. else // 已分配链表为空
  277. {
  278. malloc_allocated_list = ck;
  279. ck->next = NULL;
  280. }
  281. return (void *)(ck->start_addr + sizeof(malloc_mem_chunk_t));
  282. }
  283. /**
  284. * @brief 获取一块堆内存
  285. *
  286. * @param size 内存大小
  287. * @return void* 内存空间的指针
  288. */
  289. void *malloc(ssize_t size)
  290. {
  291. // 加上header的大小
  292. size += sizeof(malloc_mem_chunk_t);
  293. // 采用best fit
  294. malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
  295. if (ck == NULL) // 没有空闲块
  296. {
  297. // 尝试合并空闲块
  298. printf("merge\n");
  299. malloc_merge_free_chunk();
  300. ck = malloc_query_free_chunk_bf(size);
  301. // 找到了合适的块
  302. if (ck)
  303. goto found;
  304. // 找不到合适的块,扩容堆区域
  305. printf("enlarge\n");
  306. if (malloc_enlarge(size) == -ENOMEM)
  307. return -ENOMEM; // 内存不足
  308. // 扩容后再次尝试获取
  309. printf("query\n");
  310. ck = malloc_query_free_chunk_bf(size);
  311. }
  312. found:;
  313. printf("ck = %#018lx\n", (uint64_t)ck);
  314. if (ck == NULL)
  315. return -ENOMEM;
  316. // 分配空闲块
  317. // 从空闲链表取出
  318. if (ck->prev == NULL) // 当前是链表的第一个块
  319. {
  320. malloc_free_list = ck->next;
  321. }
  322. else
  323. ck->prev->next = ck->next;
  324. if (ck->next != NULL) // 当前不是最后一个块
  325. ck->next->prev = ck->prev;
  326. // 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
  327. if (ck->length - size > sizeof(malloc_mem_chunk_t))
  328. {
  329. malloc_mem_chunk_t *new_ck = ((uint64_t)ck) + size;
  330. new_ck->length = ck->length - size;
  331. new_ck->start_addr = (uint64_t)new_ck;
  332. new_ck->prev = new_ck->next = NULL;
  333. printf("new_ck=%#018lx, new_ck->length=%#010lx\n", (uint64_t)new_ck, new_ck->length);
  334. ck->length = size;
  335. malloc_insert_free_list(new_ck);
  336. }
  337. // 插入到已分配链表
  338. // 直接插入到链表头,符合LIFO
  339. ck->prev = NULL;
  340. if (malloc_allocated_list) // 已分配链表不为空
  341. {
  342. malloc_allocated_list->prev = ck;
  343. ck->next = malloc_allocated_list;
  344. malloc_allocated_list = ck;
  345. }
  346. else // 已分配链表为空
  347. {
  348. malloc_allocated_list = ck;
  349. ck->next = NULL;
  350. }
  351. printf("ck=%lld\n", (uint64_t)ck);
  352. printf("ck->start_addr=%lld\n", ck->start_addr);
  353. return (void *)(ck->start_addr + sizeof(malloc_mem_chunk_t));
  354. }
  355. /**
  356. * @brief 释放一块堆内存
  357. *
  358. * @param ptr 堆内存的指针
  359. */
  360. void free(void *ptr)
  361. {
  362. }