正確的內存管理的重要性
存在內存錯誤的 C 和 C++ 程序會導致各種問題。如果它們泄漏內存,則運行速度會逐漸變慢,并最終停止運行;如果覆蓋內存,則會變得非常脆弱,很容易受到惡意用戶的攻擊。從 1988 年著名的莫里斯蠕蟲 攻擊到有關 Flash Player 和其他關鍵的零售級程序的最新安全警報都與緩沖區溢出有關:“大多數計算機安全漏洞都是緩沖區溢出”,Rodney Bates 在 2004 年寫道。
在可以使用 C 或 C++ 的地方,也廣泛支持使用其他許多通用語言(如 Java™、Ruby、Haskell、C#、Perl、Smalltalk 等),每種語言都有眾多的愛好者和各自的優點。但是,從計算角度來看,每種編程語言優于 C 或 C++ 的主要優點都與便于內存管理密切相關。與內存相關的編程是如此重要,而在實踐中正確應用又是如此困難,以致于它支配著面向對象編程語言、功能性編程語言、高級編程語言、聲明性編程語言和另外一些編程語言的所有其他變量或理論。
與少數其他類型的常見錯誤一樣,內存錯誤還是一種隱性危害:它們很難再現,癥狀通常不能在相應的源代碼中找到。例如,無論何時何地發生內存泄漏,都可能表現為應用程序完全無法接受,同時內存泄漏不是顯而易見。
因此,出于所有這些原因,需要特別關注 C 和 C++ 編程的內存問題。讓我們看一看如何解決這些問題,先不談是哪種語言。
內存錯誤的類別
首先,不要失去信心。有很多辦法可以對付內存問題。我們先列出所有可能存在的實際問題:
•內存泄漏
•錯誤分配,包括大量增加 free() 釋放的內存和未初始化的引用
•懸空指針
•數組邊界違規
這是所有類型。即使遷移到 C++ 面向對象的語言,這些類型也不會有明顯變化;無論數據是簡單類型還是 C 語言的 struct 或 C++ 的類,C 和 C++ 中內存管理和引用的模型在原理上都是相同的。以下內容絕大部分是“純 C”語言,對于擴展到 C++ 主要留作練習使用。
內存泄漏
在分配資源時會發生內存泄漏,但是它從不回收。下面是一個可能出錯的模型(請參見清單 1):
清單 1. 簡單的潛在堆內存丟失和緩沖區覆蓋
在實際的 C 和 C++ 編程中,這不足以影響您對 malloc() 或 new 的使用,本部分開頭的句子提到了“資源”不是僅指“內存”,因為還有類似以下內容的示例(請參見清單 2)。FILE 句柄可能與內存塊不同,但是必須對它們給予同等關注:
清單 2. 來自資源錯誤管理的潛在堆內存丟失
內存錯誤分配
錯誤分配的管理不是很困難。下面是一個錯誤分配示例(請參見清單 3):
清單 3. 未初始化的指針
在此錯誤類型中存在多個變種。free() 釋放的內存比 malloc() 更頻繁(請參見清單 4):
清單 4. 兩個錯誤的內存釋放
懸空指針
懸空指針比較棘手。當程序員在內存資源釋放后使用資源時會發生懸空指針(請參見清單 5):
清單 5. 懸空指針
•即使影響提前釋放內存范圍的代碼已本地化,內存的使用仍然可能取決于應用程序甚至(在極端情況下)不同進程中的其他執行位置。
•懸空指針可能發生在以微妙方式使用內存的代碼中。結果是,即使內存在釋放后立即被覆蓋,并且新指向的值不同于預期值,也很難識別出新值是錯誤值。
懸空指針不斷威脅著 C 或 C++ 程序的運行狀態。
數組邊界違規
數組邊界違規十分危險,它是內存錯誤管理的最后一個主要類別?;仡^看一下清單 1;如果 explanation 的長度超過 80,則會發生什么情況?回答:難以預料,但是它可能與良好情形相差甚遠。特別是,C 復制一個字符串,該字符串不適于為它分配的 100 個字符。在任何常規實現中,“超過的”字符會覆蓋內存中的其他數據。內存中數據分配的布局非常復雜并且難以再現,所以任何癥狀都不可能追溯到源代碼級別的具體錯誤。這些錯誤通常會導致數百萬美元的損失。
.棘手的內存泄漏
新聞熱點
疑難解答
圖片精選