2017-03-13 82 views
1

什麼情況可以使下列代碼在以下代碼段中執行if條件?就我而言,我無法說明要執行的if語句的任何原因。Calloced內存似乎爲空

#include <stdio.h> 
#include <stdlib.h> 
void main(void){ 
int Nod = 1024 * 8; //Nod contains the number of nodes 
double *MM; //MM is a square matrix it can contain very large number of data 10^10 
MM = calloc(8 * Nod * 8 * Nod, sizeof(double)); 
if (MM == NULL)exit(0); 
//then MM will then be passed to some other functions say 
eigenvalue(MM);} 

我與具有此檢查在一個非常大的程序中間的有限元程序的工作。有趣的事實是,當我運行代碼時,它顯示了異常行爲。有時候程序就停在這裏。有時它可以正常工作。值得一提的是,當程序使用粗網格運行時,即當Nod節點數量較少時,程序運行良好。但是,當使用細網格時,程序不幸地崩潰。這個程序運行在一個有128GB RAM的迷你工作站上。該程序佔用1GB(左右)的RAM。

+2

無論採取什麼分支,該特定程序總是返回零狀態。主函數(只有主函數)有一個隱式的'return 0;'當執行到達括號後返回。 – StoryTeller

+4

'8 * Nod * 8 * Nod'是2³,所以整數溢出。使用比「int」更大的類型。 – mch

+1

閱讀calloc的手冊頁和可能的返回值。 –

回答

0

從手冊頁:

The malloc() and calloc() functions return a pointer to the allocated memory that 
    is suitably aligned for any kind of variable. On error, these functions return 
    NULL. NULL may also be returned by a successful call to malloc() with a size of 
    zero, or by a successful call to calloc() with nmemb or size equal to zero.e here 

現在,在你的情況下,它不露水分配零大小的內存中,因此唯一的其他原因返回NULL是未能分配內存。 在代碼片段中,您將分配4294967296個元素(1024 * 1024 * 64 * 64),它是32Gb內存的雙倍大小(8字節)。 現在你的系統肯定有這麼大的RAM,但是在任何給定的時間,它可能並沒有把它全部放在一個連續的可分配塊中,所以calloc可能因爲這個原因而失敗。

另一件需要注意的是主要由

/proc/sys/vm/overcommit_memory 
or vis sysctl vm.overcommit_memory 

管轄默認overcommit_memory設置爲0,但可能是最安全的組合將它設置爲2,請參見proc man頁面或內核文檔/內存過量vm/overcommit-accounting有關此更多詳細信息。

vm.overcommit_ratio 
vm.overcommit_kbytes 
vm.nr_overcommit_hugepages 

也是其他sysctl設置,管理如果/你的系統如何處理內存過度使用。

即使在這個我已經盡了最大努力不允許在32位Linux機器上過度使用內存,但我仍然能夠獲得巨大的32Gb callot不返回null(我認爲它是自己奇怪的因爲PAE少於32位的機器只能處理總共4Gb的虛擬內存,即使它具有PAE,也只能允許一次處理4Gb)。

+0

只需提一下,我正在測試該程序,現在只有4GB RAM的PC中。就在我發佈這個問題時,該程序被認爲在規定的行中失敗了。但有趣的是,該程序正在運行......!和密集的網格......!我只是想提示一下......造成這種異常行爲的原因。 –

+0

本質上,我寫了很多與Toby Speight提出的第二點相同的建議......只是更多的單詞和數字來顯示我是如何來到32Gb的。 我很奇怪,在4Gb ram機器上,你可以分配32Gb的對象......即使long的大小是一個字節(它絕對不是),它仍然會分配4Gb ... on e 4Gb的機器與實時操作系統我覺得很難相信你可以分配4Gb。也許這是虛擬的記憶:你在4Gb機器上有多少交換? – louigi600

+0

@AhmedAfifKhan這種行爲決不是「異常」 - 你實際上是在分配大量的內存,這些內存在某些時候可能會或可能不會被使用 - 而且你甚至不直接檢查返回值*分配後,你的程序失敗。 – tofro

6

兩個顯而易見的問題:

  1. 計算8 * Nod * 8 * Nodint類型,它可能不夠大(平臺)來保存結果。您可能需要size_t Nod。如果值不恆定,您可能需要檢查溢出(可能是與平臺相關的功能,例如GCC的__builtin_mul_overflow())。
  2. 您使用calloc()的結果而未檢查它是否不是NULL。如果分配器找不到足夠大的連續塊,則它將失敗,並且應該在繼續之前測試該塊。

從不忽略庫函數的返回值,它使用它來報告錯誤。

+0

如果它只是一個數據類型溢出,它不會每次都失敗嗎? – louigi600

+0

@ louigi600:這取決於。一個簽名溢出是** undefined **,所以你不能依賴任何東西。在「最佳」情況下(即最壞情況),您最終會得到一個值,當轉換爲size_t時,該值足夠大以滿足數據的要求。如果你幸運的話,你會得到一個直接的錯誤或不可取的價值,使程序崩潰並鼓勵一些調試。 –

+0

@Tony S. ok,但即便如此,他如何在虛擬內存不足的4Gb系統上分配巨大的32Gb塊呢? 我檢查了一臺32位機器(如果malloc失敗,則退出(1)),並且它正在退出0 ...這是怎麼發生的? 我很興奮! – louigi600