簡體   English   中英

包含對malloc()/ realloc()的調用......這是一個好主意嗎?

[英]Wrapping calls to malloc()/realloc()… is this a good idea?

對於賦值,我需要分配一個動態緩沖區,使用malloc()作為初始緩沖區, realloc()根據需要擴展該緩沖區。 我使用的任何地方(re | m)alloc(),代碼如下所示:

char *buffer = malloc(size);

if (buffer == NULL) {
    perror();
    exit(EXIT_FAILURE);
}

程序只讀取文件中的數據並將其輸出,所以我想當(re | m)alloc失敗時退出程序是個好主意。 現在,真正的問題是:

包裹電話是否有益,例如像這樣?

void *Malloc(int size) {
    void *buffer = malloc(size);

    if (buffer == NULL) {
        perror();
        exit(EXIT_FAILURE);
    }

    return buffer;
}

或者這是一個壞主意?

它的形式呈現一個壞主意,因為在比分配寫一個簡單的程序什么,你想要做的事更有用的/不是想逃出來優美。 所以最好不要養成壞習慣。 這並不是說分配的包裝本身是壞的(集中式錯誤處理可能是一件好事),只是你不檢查返回值的包裝器(例如,根本沒有返回的包裝器)失敗)是一個壞主意,除非你提供了一些允許代碼掛鈎到紓困邏輯的機制。

如果您確實希望以您提供的形式進行此操作,我強烈建議使用比Malloc更明顯不同的名稱而不是malloc malloc_or_die一樣。 :-)

在大多數情況下,使用空指針的嘗試無論如何都會很快崩潰程序,並且它會使調試變得更容易,因為你得到了一個很好的核心轉儲,如果你調用exit()就得不到exit()

我給出的唯一建議是在分配后盡快取消引用返回的指針,即使只是無償地使用,以便核心轉儲可以引導您直接進入錯誤的malloc調用。

你很少能從內存耗盡中恢復,所以退出通常是正確的做法。 但這樣做可以使驗屍更容易。

但需要明確的是,內存耗盡通常在操作系統被頁面交換活動削弱后很久就會發生。 這個策略實際上只對捕捉荒謬的分配很有用,比如因為bug而嘗試malloc(a_small_negative_number)。

在你的情況下,沒關系。 只記得給出一條過早退出原因的消息,指定行號會很好。 有人這樣想:

void* malloc2(int size, int line_num){
    void *buffer = malloc(size);
    if (buffer == NULL) {
        printf("ERROR: cannot alloc for line %d\n", line_num);
        perror();
        exit(EXIT_FAILURE);
        }
    return buffer;
};

#define Malloc(n) malloc2((n), __LINE__)

編輯:正如其他人提到的,對於經驗豐富的程序員來說,這不是一個好習慣,但對於一個有困難的初學者,即使在“快樂”情況下跟蹤程序流程也沒有問題。

我是否應該在我的C代碼中檢測OOM(內存不足)錯誤?

這是我對類似問題的回答。 總而言之,我贊成設計應用程序,以便從任何類型的崩潰中恢復,然后將內存不足視為崩潰的原因。

“因為過度使用而檢查malloc失敗是無用的”或者“當malloc失敗時操作系統已經癱瘓”的想法已經嚴重過時了。 強大的操作系統永遠不會過度使用內存,而且歷史上不那么強大的操作系統(如Linux)現在可以通過簡單的方法來禁用過度使用並防止操作系統因內存耗盡而癱瘓 - 只要應用程序盡其所能不崩潰malloc失敗時刻錄!

malloc在現代系統上出現故障的原因有很多:

  • 沒有足夠的物理資源來實例化內存。
  • 虛擬地址空間耗盡,即使有足夠的物理內存空閑。 這可以在具有> 4gb ram + swap的32位計算機(或32位用戶空間)上輕松實現。
  • 內存碎片。 如果您的分配模式非常糟糕,最終可能會有400萬個16字節塊,間隔1000個字節,並且無法滿足malloc(1024)調用。

如何處理內存耗盡取決於程序的性質。

當然,從系統整體健康的角度來看,你的程序死了很好。 這可以減少資源飢餓,並可能允許其他應用程序繼續運行。 另一方面,用戶將非常沮喪,如果這意味着丟失編輯視頻的工作時間,打字紙,起草博客文章,編碼等等。或者如果他們的MP3播放器突然死於外面,他們會感到高興。 -memory意味着他們的磁盤停止顛倒,他們可以回到他們的文字處理器並點擊“保存”。

至於OP的原始問題,我強烈建議不要編寫在失敗時死掉的malloc包裝器,或者編寫代碼,假設malloc失敗時只使用空指針就會立即發生段錯誤。 這是一個容易進入的壞習慣,一旦你編寫了充滿未經檢查的分配的代碼,以后在任何魯棒性都很重要的程序中重用該代碼是不可能的。

一個更好的解決方案就是保持對調用函數的返回失敗,並讓調用函數將其失敗返回到其調用函數等,直到你一直回到main或類似函數,在那里你可以編寫if (failure) exit(1); 這樣,代碼可以在其他可能實際需要檢查錯誤的情況下立即重用,並采取某種恢復步驟來釋放內存,將有價值的數據保存/轉儲到磁盤等。

我認為這是一個壞主意,因為首先檢查malloc的返回並不會對現代系統產生太大影響,其次是因為這會給你提供錯誤的安全保障,當你使用這樣的電話時,所有的分配都沒問題。

(我假設您是為托管環境而寫,而不是嵌入式,獨立。)

具有大虛擬地址空間的現代系統將永遠不會mallocrealloc分開(void*)0 ,如果參數是偽造的,也許。 你會遇到很多問題,很久以后當你的系統開始瘋狂交換甚至用完交換時。

所以不,不檢查這些功能的返回,這沒有多大意義。 相反,使用斷言檢查malloc的參數是否為0 (對於realloc如果兩者同時為0 ),那么問題不在於mallocrealloc而在於你調用它們的方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM