2015-11-29 62 views
5

我繼續試用C.我有這個程序,可以讓你決定你想要吃多少RAM。試用C - 爲什麼我不能分配和使用2GB的內存?

char * eatRAM() 
{ 
    unsigned long long toEat; 
    unsigned long long i = 0; 
    float input; 
    char * pMemory = NULL; 
    int megaByte = 1048576; 

    puts("How much RAM do you want to eat? (in Mega Bytes)"); 
    puts("NOTE: If you want to eat more RAM than you have available\nin your system, the program will crash"); 
    printf("\n>> MB: "); 
    scanf("%f", &input); 

    toEat = (unsigned long long)(input * megaByte); 
    pMemory = malloc(toEat); 

    printf("\n\nEating in total: %llu Bytes\n", toEat); 
    puts("Check your task manager!\n"); 

    if(pMemory != NULL) 
    { 
     printf("\n\nEating in total: %llu Bytes\n", toEat); 
     puts("Check your task manager!\n"); 

     for(i; i < toEat; i++) 
     { 
      pMemory[i] = 'x'; 
     } 
    } 
    else 
    { 
     puts("\nSeems like that amount of memory couldn't be allocated :(\n"); 
    } 
    return pMemory; 
} 

修訂問題:

的事情是,...如果我例如1024MB它的作品進入,我可以在任務管理器中看到它正在使用1GB的RAM。即使我進入1500MB它的工作原理..

但是,如果我進入2048MB它說

好像無法分配:(

或內存量即使我輸入1756MB

記住我是C新手,也許我正在省略一些重要的關聯編輯如何OS允許我訪問內存,它可能是什麼?

+0

malloc可能會失敗並返回null,請檢查 –

+0

由於您嘗試訪問內存,儘管分配失敗,您必須在嘗試使用它之前檢查'pMemory!= NULL'。另外,你不應該強制使用'malloc()',一般不會從'void *'強制轉換爲其他指針。 –

+0

你的電腦有多少內存? –

回答

5

Windows上的32位進程默認具有2千兆字節的地址空間。完整pow(2,32)地址空間的下半部分,操作系統使用前2 GB。由於幾乎沒有人使用32位操作系統,因此當您將程序與/ LARGEADDRESSAWARE關聯時,可以獲得4 GB的空間。

2 GB虛擬機空間需要被代碼和數據共享。您的程序通常在0x00400000加載,您使用的任何操作系統DLL(如kernel32.dll和ntdll.dll)具有高負載地址(超出0x7F000000)。至少啓動線程的堆棧和默認進程堆是在程序開始運行之前創建的,它們的地址通常是不可預知的。

在大多數任何操作系統安裝中,您的程序將受到縮小包裝的病毒攻擊,您將注入DLL,以提供反惡意軟件和雲存儲等「服務」。這些DLL的加載地址是不可預知的。此外,您與自己鏈接的任何DLL都會在程序啓動時隱式加載。很少有程序員注意他們的首選基地址,並將其保留在默認值0x1000000處。您可以從調試器的「模塊」窗口中看到這些DLL。這樣的DLL往往有自己的CRT,並傾向於創建自己的堆。

你自己做的分配,特別是非常大的不會來自低碎片堆的分配,需要在現有代碼和數據分配之間的空洞中找到地址空間。如果你得到1500 MB,那麼你的VM很乾淨。一般情況下,如果程序運行一段時間並使VM空間碎片化,您將會遇到超過650 MB的問題,並快速減少。分配失敗幾乎總是因爲操作系統找不到足夠大的空洞而導致的,而不是因爲您沒有足夠的虛擬機。這些空洞的總和可能會比失敗的分配請求大得多。

這些細節正在迅速成爲一個民間故事,還有很少的剩餘理由仍然針對x86。目標x64和地址空間碎片在未來20年不會成爲問題,很難分割8 TB的虛擬機。有很多的空間可以超出這個範圍。

所以它應該很明顯,爲什麼你不能得到2048 MB,你不能得到它。從SysInternals'VMMap utility獲得進一步的信息,它顯示了虛擬機是如何分割的。和馬克Russinovich'blog post和書給了很多背景。

+0

謝謝你花時間給予這樣一個很好的支持答案!要繼續研究和練習! - 乾杯! –

0

如果剩餘空閒內存的數量少於您要分配的數量,分配將無法執行。

而且,這條線之後:

pMemory = (char *) malloc(toEat); 

添加以下內容:

if (!pMemory){ 
    printf("Can't allocate memory\n"); 
    return NULL; 
} 

通過這種方式,而不是接收 「分段錯誤」 相關的消息,你會看到一個「能」 t分配內存「消息,而你的函數將返回NULL。

確保您在調用您的eatRam函數的函數中執行類似的值檢查,否則您將收到「段錯誤」消息。並且使用像gdb這樣的調試器。

+1

謝謝邁克回覆。實際上,在運行2048MB測試時,我有超過5GB的可用內存,您怎麼看?此外,我幾分鐘前更新了我的代碼,以便正確處理malloc的返回。再次感謝! –

+2

@JuanBonnett請注意,使用'malloc'意味着你正在使用的內存是一個巨大的代碼塊,即使你有2到3 GB的空閒內存,它可能沒有(可以說)1GB的空閒塊。另外,我認爲我在某處因爲這個原因,Windows有一些「塊限制」,所以應用程序不會嘗試從其他應用程序或類似的東西中分配內存。 – TomTsagk

3

這是一個操作系統限制,而不是C限制。

要解決超過4Gb系統範圍,您需要運行64位操作系統,並且爲了解決超過4Gb的單個進程,它必須構建爲64位應用程序。 Win32的每個進程內存限制爲2Gb。由於內存是虛擬化的,因此5Gb的物理RAM在很大程度上無關緊要。

與32位和64位系統和應用程序的理論極限不同,操作系統可能仍會施加限制。出於商業原因,Windows的不同版本(家庭版,專業版,服務器等)例如施加了特定的限制。

您的情況的具體答案將需要有關您的系統,工具鏈和構建選項的信息。如果您使用Windows和VC++,則需要考慮/LARGEADDRESAWARE選項;它在32位編譯器中並未默認啓用,但Win32的默認限制爲2Gb,除非啓用physical address extension

我相信在Win64上運行的32位進程可以解決完整的4Gb 32位地址空間,但在這種情況下,您肯定需要使用/LARGEADDRESAWARE進行構建。即使沒有那麼多空間可用於堆,並且任何單個分配都必須是連續的,因此可能會受到之前分配和堆碎片的限制。

+0

感謝您花時間給予這樣一個良好支持的答案!要繼續研究和練習! - 乾杯! –

相關問題