--- tags: 你所不知道的 C 語言, 進階電腦系統理論與實作, NCKU Linux Kernel Internals, 作業系統 --- # 記憶體管理、未定義行為 contributed by <`RusselCK` > ###### tags: `RusselCK` ## [記憶體管理](https://hackmd.io/@sysprog/c-memory?type=view) ### alignment、pedding、pack ![](https://i.imgur.com/wIfEVy9.png) --- 參照 [What a C programmer should know about memory](https://marek.vavrusa.com/memory/) ([簡記](http://wen00072.github.io/blog/2015/08/08/notes-what-a-c-programmer-should-know-about-memory/)) * Understanding virtual memory - the plot thickens > The virtual memory allocator (VMA) may give you a memory it doesn’t have, all in a vain hope that you’re not going to use it. Just like banks today :::info 1. 現代銀行和虛擬記憶體兩者高度相似 2. malloc 給 valid pointer不要太高興,等你要開始用的時候搞不好作業系統給個 OOM。簡單來說就是一張支票,能不能拿來開等到兌現才知道 ::: --- malloc 本來配置出來的記憶體位置就有做 alignment,根據 malloc 的 man page 裡提到 : > The malloc() and calloc() functions return a pointer to the allocated memory, which is suitably aligned for any built-in type. 實際上到底 malloc 做了怎樣的 data alignment,繼續翻閱 [The GNU C Library - Malloc Example](ftp://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.3/html_node/libc_25.html),裡面有特別提到 : > In the GNU system, the address is always a multiple of eight on most systems, and a multiple of 16 on 64-bit systems. 這句我就有看懂,所以說在大多數系統下,malloc 會以 8 bytes 進行對齊;而在 64-bit 的系統下,malloc 則會以 16 bytes 進行對齊。 考慮以下 `unaligned_get32` 函式的實作: (假設硬體架構為 32-bits) ```cpp #include <stdint.h> #include <stddef.h> uint8_t unaligned_get8(void *src) { uintptr_t csrc = (uintptr_t) src; uint32_t v = *(uint32_t *) (csrc & 0xfffffffc); v = (v >> (((uint32_t) csrc & 0x3) * 8)) & 0x000000ff; return v; } uint32_t unaligned_get32(void *src) { uint32_t d = 0; uintptr_t csrc = (uintptr_t) src; for (int n = 0; n < 4; n++) { uint32_t v = unaligned_get8((void *) csrc); v = v << (n * 8); d = d | v; csrc++; } return d; } ``` 對應的 `unaligned_set32` 函式: ```cpp void unaligned_set8(void *dest, uint8_t value) { uintptr_t cdest = (uintptr_t) dest; uint32_t d = *(uint32_t *) (cdest & 0xfffffffc); uint32_t v = value; for (int n = 0; n < 4; n++) { uint32_t v = unaligned_get8((void *) csrc); v = v << (n * 8); d = d | v; csrc++; } return d; } void unaligned_set32(void *dest, uint32_t value) { uintptr_t cdest = (uintptr_t) dest; for (int n = 0; n < 4; n++) { unaligned_set8((void *) cdest, value & 0x000000ff); value = value >> 8; cdest++; } } ``` --- **malloc流程** * 調整 malloc size : 加上 overhead 並對齊,若 < 32 byte(64bit 最小 size,4 pointers)則補上 * 檢查 fastbin : 若對應 bin size 有符合 chunk 即 return chunk * 檢查 smallbin : 若對應 bin size 有符合 chunk 即 return chunk * 合併(consolidate) fastbin : (若 size 符合 large bin 或前項失敗)呼叫 malloc_consolidate 進行 fastbin 的合併(取消下一 chunk 的 PREV_INUSE),並將合併的 bin 歸入 unsorted * 處理 unsorted bin : * 若 unsorted bin 中只有 last_remainder 且大小足夠,分割 last_remainder 並return chunk。剩下的空間則成為新的 last_remainder * loop 每個 unsorted bin chunk,若大小剛好則 return,否則將此 chunk 放至對1應 size 的 bin 中。此過程直到 unsorted bin 為空或 loop 10000次為止 * 在 small / large bin 找 best fit,若成功則 return 分割的 chunk,剩下的放入 unsorted bin(成為 last_remainder);若無,則繼續 loop unsorted bin,直到其為空 * 使用 top chunk : 分割 top chunk,若 size 不夠則合併 fastbin,若仍不夠則 system call **free流程** * 檢查 : 檢查 pointer 位址、alignment、flag 等等,以確認是可 free 的 memory * 合併(consolidate) * fastbin size : 不進行合併 * 其他 : * 檢查前一 chunk,若未使用則合併 * 檢查後一 chunk,若是 top chunk 則整塊併入 top chunk,若否但未使用,則合併 * 將合併結果放入 unsorted bin * ref : [allocation過程](http://brieflyx.me/2016/heap/glibc-heap/) * **glibc malloc allocation informations** * [mallinfo](http://man7.org/linux/man-pages/man3/mallinfo.3.html) - obtain memory allocation information * [malloc_stats](http://man7.org/linux/man-pages/man3/malloc_stats.3.html) - print memory allocation statistics * [malloc_info](http://man7.org/linux/man-pages/man3/malloc_info.3.html) - export malloc state to a stream 簡單測試 : malloc(40 * sizeof(int)); * mallinfo() [example](http://man7.org/linux/man-pages/man3/mallinfo.3.html#EXAMPLE) ```shell Total non-mmapped bytes (arena): 135168 # of free chunks (ordblks): 1 # of free fastbin blocks (smblks): 0 # of mapped regions (hblks): 0 Bytes in mapped regions (hblkhd): 0 Max. total allocated space (usmblks): 0 Free bytes held in fastbins (fsmblks): 0 Total allocated space (uordblks): 176 Total free space (fordblks): 134992 Topmost releasable block (keepcost): 134992 ``` --- ## [未定義行為](https://hackmd.io/@sysprog/c-undefined-behavior?type=view)