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