--- tags: sysprog --- # [你所不知道的 C 語言:記憶體管理、對齊及硬體特性篇](https://www.youtube.com/watch?v=v2Lj7lI_7ig&feature=youtu.be) ### 你可能沒想過的 Memory 1. malloc有可能不成功,即便回傳valid pointer也不一定能用! 因為當我們 malloc() 的時候,記憶體預設是允許==overcommit==的,如果記憶體實際有32MB,但你可以malloc遠超32MB。 但這可能會導致非常糟糕的結果 - 宣告時沒事,但真去操作時卻會把任意 process 殺掉。 >alloc 給 valid pointer不要太高興,等你要開始用的時候搞不好作業系統給個 OOM。簡單來說就是一張支票,能不能拿來開等到兌現才知道 OOM Killer (Out-Of-Memory Killer),他會在沒有記憶體不夠用時會被喚醒,並砍掉一些 process 以釋放記憶體給你用。 但你無法確定到底哪些會被砍,甚至連你自己都會被砍。 所以也有人認為這個從 overcommit 到 OOM Killer 的機制根本就是個Bug 2. mlock : `mlock`要求(不一定會被O.S接受)特定記憶體區塊常駐於此,而不會被置換 ( swap out ) 到硬碟的`/swap`裡面。 ### data alignment 3. data alignment 的意思就是, data 的 address 可以公平的被 1, 2, 4, 8,這些 $2^N$數字整除 4. 編譯器會幫你想辦法做data alignment 如果有一 structure 是 `int` + `char`,雖然在 C 裡面他的大小應是 5 bytes,但是考慮到對齊,為了存取 `int` 他需要 4 bytes 的倍數 ,所以編譯器會自動安排 8 ( 4 x 2 ) bytes 空間給你。 ```clike #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct _s1 { char a; int b; } s1; int main() { s1 p[10]; printf("struct s1 size: %ld byte\n", sizeof(s1)); for(int i = 0; i < 5; i++) { printf("the struct p[%d] address =%p\n", i, p + i); } } ``` ``` struct s1 size: 8 byte the struct p[0] address =0x7ffe803b08a0 the struct p[1] address =0x7ffe803b08a8 the struct p[2] address =0x7ffe803b08b0 the struct p[3] address =0x7ffe803b08b8 the struct p[4] address =0x7ffe803b08c0 ``` *注意 : 為了對齊的效率,編譯器有可能把`int`擺在前頭`char`在後頭,跟程式碼順序不同* 但是,如果有另一 structure 是 `char[5]`,大小同樣是 5 bytes,單卻不會如同上述分配 8 bytes,但因為此結構都是`char`,data alignment 會是 1 bytes,所以也就沒什麼好對齊的。 ```clike // ... typedef struct _s1 { char a[5]; } s1; // ... ``` ``` struct s1 size: 5 byte the struct p[0] address =0x7ffd701df160 the struct p[1] address =0x7ffd701df165 the struct p[2] address =0x7ffd701df16a the struct p[3] address =0x7ffd701df16f the struct p[4] address =0x7ffd701df174 ``` 5. pack 跟 alignment 是成對的 `#pragma pack()` 是 告訴編譯器 「我期望多大,最終就該配置多大,且資料排列順序要跟我預期的一樣。」,這可以解決上述第 4 點所說的「編譯器自動幫你安排資料順序」的情況,這些嚴格限制的特性主要是運用在網路封包的處理上。 ```clike #pragma pack(1) typedef struct _test1 { char c[3]; int num[256]; } test1; #pragma pack(pop) typedef struct _test2 { char c[3]; int num[256]; } test2; ``` 所以,如上 test1 結構,他的大小就會是 1027 (3+1024) bytes,且 `char[3]` 一定會排在 `int[256]` 前面。 但現在處理器對 misalignment 已經有很大的改良,一般狀況下效率不會差太多。 6. 在64位元電腦中,C 的 malloc() 會以 16 bytes 做 data alignment > In the GNU system, the address is always a multiple of eight on most systems, and a multiple of 16 on 64-bit systems. 8. 注意,對於 unaligned data的存取,某些處理器的硬體架構是可以支援的,但對於效能有很大的拖垮。 某些處理器的硬體架構則根本不允許你做如此的記憶體存取,會回傳給你錯誤訊息。 更甚者,某些處理器會在沒有任何警告情況下回傳你**錯誤的資料** ! 所以,探討 alignment 議題,就是為了讓你能夠寫的軟體能夠「跨平台」,從嵌入式到超級電腦,在面對對應不同的處理器、不同的硬體架構都能執行正確的行為。 ### Misalignment data v.s unaligned data misalignment data 是「資料存放位置不好,導致取一次資料處理器就得三番兩次對記憶體做access,再把好幾個區塊中部分會用到的資料做剪裁、拼接」。 unaligned data 則是「對於那些位置不好的資料,我不照規矩 ( 照alignment ) 一個一個區塊取出來再拼貼,而是把處理器指向非區塊起點的記憶體位址去存取資料」。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up