2013-08-19 65 views
2

我很困惑內存分配(malloc/calloc)如何在linux/c中工作。假設,我有一臺擁有16GB RAM的機器,我以root身份運行一個程序。它是64位機器,因此所有16GB都可以作爲一個單獨的網段尋址。我可以通過一次malloc調用來分配所有這些(減少操作系統的數量)嗎?有很多malloc調用?內存分配如何在極端情況下工作?

怎麼看都涉及到「堆內存」和「虛擬內存」?如果我分配一個小內存塊,它發生在堆內存中,那麼我調整(放大)這個塊,當我接近堆棧區時會發生什麼?

我必須通過setrlimit RLIMIT_AS亂動,如果我想(幾乎)所有的RAM被分配給我的一個進程,甚至認爲它是作爲root運行?

+2

一般被推向後備存儲(盤),因爲你有虛擬內存管理,因此可以分配超過16GB,這取決於你的交換空間大小。然而,精彩的表演並不能保證。 – Jiminion

+3

它可能是一個64位機器......但它是一個64位*進程*?它有所作爲。 – WhozCraig

+1

嘗試'printf(「%p \ n」,malloc(16ull * 1024 * 1204 * 1204))'並找出答案。 – chux

回答

0

64位進程可以分配所有的內存。它甚至不需要是root用戶,除非系統爲非root用戶定義了ulimit設置。嘗試ulimit -v以查看是否設置了限制。

Linux下的默認設置的過程中可以要求幾乎所有的內存量,這將被授予。內存將按照使用情況進行實際分配,它將根據需要來自物理RAM或磁盤交換。

內存分配調整大小通常在C庫通過分配新的,更大的尺寸和舊的數據複製到新的分配來完成。這通常不是通過擴大現有分配來完成的。內存分配選擇爲不與其他分配(如程序堆棧)衝突。

2

malloc()可以通過擴展堆或通過足夠大的內存塊來分配內存。他們使用哪一種取決於你要求的尺寸和幾個選項。

如果它使用通常位於虛擬內存區域起始處的「真正的」堆區段,它可以增長到它碰到下一個分配的內存區塊的位置,該區塊離開始處很遠。

如果使用mmap(),這取決於是否有可用連續的地址空間。

/proc/<PID>/maps是找出一個進程的地址空間的情況下良好的查詢點。

我只是用我的Python和ctypes的64位服務器測試:

import ctypes 
import ctypes.util 
m=ctypes.CDLL(ctypes.util.find_library("c")).malloc 
m.argtypes=(ctypes.c_uint64,) 
m.restype = ctypes.c_uint64 

現在我有m,作爲對libc中的malloc()函數的調用。現在

我可以做

>>> hex(m(2700000000)) 
'0x7f1345e3b010L' 
>>> hex(m(2700000000)) 
'0x7f12a4f4f010L' 
>>> hex(m(2700000000)) 
'0x7f1204063010L' 
>>> hex(m(2700000000)) 
'0x7f1163177010L' 
>>> hex(m(2700000000)) 
'0x7f10c228b010L' 
>>> hex(m(2700000000)) 
'0x7f102139f010L' 
>>> hex(m(2700000000)) 
'0x7f0f804b3010L' 

但不論何種原因,我不能做

>>> hex(m(2900000000)) 
'0x0L' 

因爲它返回0 RESP。一個NULL指針。

現在

print open("/proc/self/maps").read() 

做給我看說文件的行;在某處

7f0ed8000000-7f0ed8021000 rw-p 00000000 00:00 0 
7f0ed8021000-7f0edc000000 ---p 00000000 00:00 0 
7f0edf5c7000-7f13e6d27000 rw-p 00000000 00:00 0 

我得到了我的分配。

但是,如果我這樣做,而不是

>>> hex(m(1)) 
'0x1f07320L' 
>>> hex(m(1)) 
'0x1f0c0e0L' 
>>> hex(m(1)) 
'0x1f02d50L' 
>>> hex(m(1)) 
'0x1f02d70L' 
>>> hex(m(1)) 
'0x1ef94f0L' 
>>> hex(m(1)) 
'0x1eb7b20L' 
>>> hex(m(1)) 
'0x1efb700L' 
>>> hex(m(270)) 
'0x1f162a0L' 
>>> hex(m(270)) 
'0x1f163c0L' 
>>> hex(m(270)) 
'0x1f164e0L' 
>>> hex(m(270)) 
'0x1f16600L' 

的內存地址來自

>>> print open("/proc/self/maps").read() 
[...] 
01d2e000-01f2b000 rw-p 00000000 00:00 0         [heap] 
[...] 

指定的堆。

請注意,雖然我可以分配此內存,但使用它會造成傷害,因爲我的進程可能會被着名的OOM殺手殺死。

5

在虛擬內存操作系統(如Linux)上malloc()不分配內存。它分配地址空間例如,編譯和運行下面的片段,和(在另一端)運行top

#include <stdlib.h> 
#include <unistd.h> 

int main(void) { 
    char *cp; 
    cp = malloc(16ULL * 1024 *1024 *1024); 
    if (cp) pause(); 
    return 0; 
} 

在我的電腦,TOP顯示:

PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND    
29026 plasser 20 0 16.0g 324 248 S 0 0.0 0:00.00 a.out 

這意味着:一個.out具有16GB虛擬大小,並且僅使用324(bytes?KB?)常駐內存(可能只是二進制文件)

發生了什麼?

  • 的malloc()函數呼叫已要求OS延長地址空間,加入16 GB
  • 操作系統已經滿足這一要求,並設置爲它等等pagetables。
  • 這些頁表有附加他們(還)沒有物理內存,也許除了自己
  • 一旦程序開始引用此地址空間,頁面將被連接的表(操作系統WIL 責怪他們在
  • (頁面可能會從/ dev/zero中刪除,但這只是一個細節)
  • 但是,在程序確實引用地址的時候,內存將不得不由OS併成爲附加的過程。 (並且它會顯示在RES字段中,請相信我)
  • 在某些時候,附加內存也可能被分離,一旦OS認爲它已經很長時間沒有被使用。它將被添加到一個可用內存池或/和用於其他目的。其內容可在這種情況下

`

+1

我不得不承認,作爲一名本土的荷蘭語演講者,我最初受到'top'返回的'USER'的輕微干擾 – Pankrates

+0

@Pankrates我只是繼續前進和谷歌粘貼。有一個很好的笑聲。 – UmNyobe

相關問題