成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

撥開由問題《Linux下malloc最大可申請的內(nèi)存》帶來的重重疑云

trilever / 978人閱讀

摘要:本文測試環(huán)境如下一首先需要考慮的幾個問題我們使用申請到的是物理內(nèi)存嗎使用能申請到的只有的物理內(nèi)存嗎申請到的內(nèi)存大小全都可以被用來嗎以上三個問題,正是本次所要討論的內(nèi)容。

今天閱讀相關(guān)書籍的時候看到 "進程中堆的最大申請數(shù)量" 這一問題,我們知道使用malloc分配內(nèi)存是在堆Heap里面分配的,如果一臺機器一共有8GB物理內(nèi)存,空閑5GB,那么我們使用malloc( )就一定能夠申請到這5GB內(nèi)存嗎?理論上來說確實如此,因為這些內(nèi)存未被其它進程使用。但實際測試出來結(jié)果卻可能令人疑惑。

本文測試環(huán)境如下:

1 qi@qi:~$ uname -a2 Linux qi 5.4.0-89-generic #100~18.04.1-Ubuntu SMP Wed Sep 29 10:59:42 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux?

?


?一、首先需要考慮的幾個問題

  1. 我們使用malloc( )申請到的是物理內(nèi)存嗎?
  2. 使用malloc( )能申請到的只有8GB的物理內(nèi)存嗎?
  3. malloc( )申請到的內(nèi)存大小全都可以被用來memset( )嗎?

以上三個問題,正是本次所要討論的內(nèi)容?,F(xiàn)在假定認為以上三個陳述均正確,那么我們可以用以下程序測試malloc( )可以申請的內(nèi)存大小:

 1 #include  2 #include  3 #include <string.h> 4  5 unsigned long long int maximum = 0; 6  7 int main (int argc, char* argv[]) 8 { 9     unsigned int block_size[] = {1024*1024, 1024, 1};10     int i, count;11 12     for( int i=0; i<3; i++) {13         for(count=1;; count++) {14             void *block = malloc(maximum + block_size[i]*count);15             if( block ) {16                 //memset(block, 0, maximum + block_size[i]*count);17                 free(block);18                 maximum = maximum + block_size[i]*count;19             } else {20                 break;21             }22         }23     }24 25     printf("maximum malloc size is %llu bytes /n", maximum);26 27     return 0;28 }

?運行以上程序,得到輸出為:

1 root@qi:/home/qi/test_park/elf_load# ./main 2 maximum malloc size is 24587279333 bytes

?可以看到,以上測試程序最大申請到了 22.9GB 的內(nèi)存,但是我的機器上實際內(nèi)存有多少呢?如下:

1 qi@qi:~/test_park/elf_load$ free2               total        used        free      shared  buff/cache   available3 Mem:        8011016     2373760     3517884      719508     2119372     46546404 Swap:      15999996           0    15999996

很明顯,機器上最大的物理內(nèi)存也沒到8GB,如果你了解swap 交換空間,可能會說Mem項和Swap項的total加起來似乎正好是22.9GB,但是另外一個問題有來了,那就是這些內(nèi)存或者交換空間并不是全部空閑,包括系統(tǒng)內(nèi)核和系統(tǒng)界面等等也要占用一部分物理內(nèi)存,所以我們看到Mem項的 "available"的可用內(nèi)存只有大約4.5GB,所以結(jié)果就是,malloc( )申請到的內(nèi)存數(shù)量是遠遠大于我們實際的物理內(nèi)存的。既然malloc( )函數(shù)的實際輸出和我們的預(yù)期不相符,那是不是我們哪里用錯了呢?不妨使用"man malloc"查看對其的官方解釋:

1 NOTES2        By default, Linux follows an optimistic memory allocation strategy.  This means that when malloc() returns non-NULL there is no guarantee that the mem‐3        ory really is available.  In case it turns out that the system is out of memory, one or more processes will be killed by  the  OOM  killer.   For  more4        information,  see  the  description  of /proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file Documenta‐5        tion/vm/overcommit-accounting.

?果不其然,Note中說明了就算malloc( )返回非NULL指針也不能保證該指針指向的內(nèi)存區(qū)域全都可以被該進程使用。那么為什么會這樣呢?后面有提示,首先涉及到的最重要的一個設(shè)置就是 "/proc/sys/vm/overcommit_memory" 這一個文件,使用 "man proc" 找到有關(guān)其的說明:

 1        /proc/sys/vm/overcommit_memory 2               This file contains the kernel virtual memory accounting mode.  Values are: 3  4                      0: heuristic overcommit (this is the default) 5                      1: always overcommit, never check 6                      2: always check, never overcommit 7  8               In mode 0, calls of mmap(2) with MAP_NORESERVE are not  checked,  and  the  default 9               check is very weak, leading to the risk of getting a process "OOM-killed".10 11               In mode 1, the kernel pretends there is always enough memory, until memory actually12               runs out.  One use case for this mode is  scientific  computing  applications  that13               employ  large  sparse  arrays.   In Linux kernel versions before 2.6.0, any nonzero14               value implies mode 1.15 16               In mode 2 (available since Linux 2.6), the total virtual address space that can  be17               allocated (CommitLimit in /proc/meminfo) is calculated as18 19                   CommitLimit = (total_RAM - total_huge_TLB) *20                                 overcommit_ratio / 100 + total_swap

可以看到,如果該文件內(nèi)容為0,mmap(malloc的內(nèi)部調(diào)用)將不檢查,有導(dǎo)致使用不存在內(nèi)存的風(fēng)險,如果文件內(nèi)容為1,則malloc( )可以申請的內(nèi)存可以非常大,我的機器上經(jīng)過測試可以達到90T,如果該文件內(nèi)容為2,那么所有可以申請的內(nèi)存為 "CommitLimit",具體可以通過公式或者 "cat /proc/meminfo | grep Limit"查看大小。那么這就能說通為什么上面的程序可以malloc( )出22GB多的內(nèi)存了,查看 "/proc/sys/vm/overcommit_memory" 果不其然,內(nèi)容為0:

1 root@qi:/home/qi/test_park/elf_load# cat /proc/sys/vm/overcommit_memory 2 0

以上回答了第2個問題中的一部分,那就是某些設(shè)置下,malloc( )可以申請到超出機器物理內(nèi)存的大小,為什么說是一部分呢,因為可申請的內(nèi)存不僅和上述設(shè)定相關(guān),還和機器的swap space相關(guān),如果你不了解或者沒聽過( 事實上在你給你機器裝Linux系統(tǒng)的時候應(yīng)該碰到過,那就是磁盤分區(qū)的時候會有一個swap設(shè)定)swap空間,只需要知道它是一種掛載在物理硬盤上,用來存放一些不太頻繁使用的內(nèi)存,是一種低速的物理內(nèi)存的擴展,當(dāng)物理內(nèi)存不夠用時,原先一些物理內(nèi)存中不常訪問的內(nèi)容會被轉(zhuǎn)移到這里以讓出空間給其它進程。所以swap空間也可以被malloc( )申請到。

由此,第2個問題得到了全部的解答。這個時候你可能會說,第1個問題應(yīng)該也有答案了,因為malloc( )不僅申請了8GB的物理內(nèi)存,還申請了15GB的swap硬盤空間作為擴展內(nèi)存,甚至還可以申請大約90TB的不存在的內(nèi)存,所以第一個問題就解決了嗎?

其實對,但也不全對,因為malloc( )這個時候申請了內(nèi)存,但沒有完全申請,這就涉及到一個叫做 "Lazy Allocation" 的東東,類似于fork的寫時復(fù)制機制,當(dāng)你使用malloc( )時,系統(tǒng)并沒有真正從物理內(nèi)存中分配,而是等到進程要操作時才提供allocation,這也就解釋了我們剛開頭申請了22.9GB的內(nèi)存都還沒有報段錯誤的原因。只有當(dāng)你access這個內(nèi)存區(qū)域的時候才會真正分配,所以我們可以大膽的在程序里面加上memset,把上面貼出的代碼的memset那一行取消掉注釋,然后再運行。如果你不想等太久,可以像我這樣:

1 root@qi:/home/qi/test_park/elf_load# echo 0 >  /proc/sys/vm/overcommit_memory 2 root@qi:/home/qi/test_park/elf_load# swapoff -a3 root@qi:/home/qi/test_park/elf_load# echo 2 >  /proc/sys/vm/overcommit_memory

以上命令是把交換空間禁用,這樣就可以減少可使用的內(nèi)存了,關(guān)閉交換空間后,如果/proc/sys/vm/overcommit_memory內(nèi)容為0,那么你可以malloc( )的內(nèi)存大小應(yīng)該為8GB左右,但是不是每一個字節(jié)都可以memset,大可以測試一下,會發(fā)現(xiàn)memset了6~7GB的內(nèi)存空間后程序報錯異常退出,這是因為這個時候可使用的內(nèi)存也就這么大,這種情況下隨意使用malloc( )申請到的內(nèi)存是不安全的。如果/proc/sys/vm/overcommit_memory內(nèi)容為2,那么這個時候可申請的內(nèi)存就得看 "CommitLimit" 了,在我的機器上測試是只能申請1.5GB左右,這種情況下無論如何也不會訪問非法內(nèi)存區(qū)域了,但是一個缺點是不能使用全部的空閑內(nèi)存,只能修改相應(yīng)的設(shè)置。

那么該如何知道實際可用的內(nèi)存大小呢?一種解決方案是查看 "/proc/meminfo" 中的available memory,乘個安全系數(shù)再來申請。

以上,三個問題全都被解決,離專業(yè)的linuxer又近了一步~

?

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/124812.html

相關(guān)文章

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<