記憶體洩漏是計算機科學中的一種資源洩漏，主因是計算機程式的記憶體管理失當，因而失去對一段已分配記憶體空間的控制，程式繼續佔用已不再使用的記憶體空間，或是記憶體所儲存之物件無法透過執行程式碼而存取，令記憶體資源空耗。 記憶體漏失與許多其他問題情形具有相同徵兆，通常只有獲得程式原始碼的程式設計師能分析診斷是否發生記憶體漏失。 後果 記憶體洩漏會因為減少可用記憶體的數量從而降低計算機的效能。最終，在最糟糕的情況下，過多的可用記憶體被分配掉導致全部或部分裝置停止正常工作，或者應用程式崩潰。 記憶體洩漏帶來的後果可能是不嚴重的，有時甚至能夠被常規的手段檢測出來。在現代作業系統中，一個應用程式使用的常規記憶體在程式終止時被釋放。這表示一個短暫執行的應用程式中的記憶體洩漏不會導致嚴重後果。 在以下情況，記憶體洩漏後果較嚴重： 程式執行後置之不理，並且隨著時間的流逝消耗越來越多的記憶體（比如伺服器上的後臺任務，尤其是嵌入式系統中的後臺任務，這些任務可能被執行後很多年內都置之不理）； 新的記憶體被頻繁地分配，比如當顯示電腦遊戲或動畫影片畫面時； 程式能夠請求即使在程式終止之後也不會被釋放的記憶體（比如共享記憶體）； 洩漏在作業系統內部發生； 洩漏在系統關鍵驅動中發生； 記憶體非常有限，比如在嵌入式系統或便攜裝置中； 當運行於一個程式終止時記憶體並不自動釋放記憶體的作業系統（比如 AmigaOS）之上時。 簡例 以下的虛構例子無需任何程式設計的知識，但能表明如何導致記憶體洩漏及其造成的影響。 在此例中的應用程式是一個簡單軟體的一小部分，用來控制升降機的運作。此部分軟體當乘客在升降機內按下一樓層的按鈕時執行。 當按下按鈕時： 要求使用記憶體，用作記住目的樓層 把目的樓層的數字儲存到記憶體中 升降機是否已到達目的樓層？ 如是，沒有任何事需要做：程式完成 否則： 等待直至升降機停止 到達指定樓層 釋放剛才用作記住目的樓層的記憶體 此程式有一處會造成記憶體洩漏：如果在升降機所在樓層按下該層的按鈕（即上述程式的第 4 步），程式將觸發判斷條件而結束執行，但記憶體仍一直被佔用而沒有被釋放。這種情況發生得越多，洩漏的記憶體也越多。 這個小錯誤不會造成即時影響。因為人不會經常在升降機所在樓層按下同一層的按鈕。而且在通常情況下，升降機應有足夠的記憶體以應付上百次、上千次類似的情況。不過，升降機最後仍有可能消耗完所有記憶體。這可能需要數個月或是數年，所以在簡單的測試下這個問題不會被發現。 而這個例子導致的後果會是不那麼令人愉快。至少，升降機不會再理會前往其他樓層的要求。更嚴重的是，如果程式需要記憶體去開啟升降機門，那可能有人被困升降機內，因為升降機沒有足夠的記憶體去開啟升降機門。 記憶體洩漏只會在程式執行的時間內持續。例如：關閉升降機的電源時，程式終止執行。當電源再度開啟，程式會再次執行而記憶體會重置，而這種緩慢的洩漏則會從頭開始再次發生。 程式設計問題 記憶體洩漏是程式設計中一項常見錯誤，特別是使用沒有內建自動垃圾回收的程式語言，如 C 及 C。一般情況下，記憶體洩漏發生是因為不能存取動態分配的記憶體。目前有相當數量的除錯工具用於檢測不能存取的記憶體，從而可以防止記憶體洩漏問題，如、、Valgrind、及都是為 C／C 程式設計亦較受歡迎的記憶體除錯工具。垃圾回收則可以應用到任何程式語言，而 C／C 也有此類函式庫。 提供自動記憶體管理的程式語言如 Java、C、C、VBNET 以及 LISP，都不能避免記憶體洩漏。例如，程式會把專案加入至列表，但在完成時沒有移除，如同人把物件丟到一堆物品中或放到抽屜內，但後來忘記取走這件物品一樣。記憶體管理器不能判斷專案是否將再被存取，除非程式作出一些指示表明不會再被存取。 譬如以 C 語言為例，在 stdlibh 中提供了 malloc 、calloc 、free 等函式，在使用 malloc 取得記憶體空間，則需在不需使用後 free 釋放，如未釋放，則會產生所謂 memory leakage。 雖然記憶體管理器可以回復不能存取的記憶體，但它不可以釋放可存取的記憶體因為仍有可能需要使用。現代的記憶體管理器因此為程式設計員提供技術來標示記憶體的可用性，以不同級別的「存取性」表示。記憶體管理器不會把需要存取可能較高的物件釋放。當物件直接和一個強引用相關或者間接和一組強引用相關表示該物件存取性較強。（強引用相對於弱引用，是防止物件被回收的一個引用。）要防止此類記憶體洩漏，開發者必須使用物件後清理引用，一般都是在不再需要時將引用設成 null，如果有可能，把維持強引用的事件偵聽器全部登出。 一般來說，自動記憶體管理對開發者來講比較方便，因為他們不需要實現釋放的動作，或擔心清理記憶體的順序，而不用考慮物件是否依然被引用。對開發者來說，瞭解一個引用是否有必要保持比了解一個物件是否被引用要簡單得多。但是，自動記憶體管理不能消除所有的內容洩漏。 影響 如果一個程式存在記憶體洩漏並且它的記憶體使用量穩定增長，通常不會有很快的症狀。每個物理系統都有一個較大的記憶體量，如果記憶體洩漏沒有被中止（比如重啟造成洩漏的程式）的話，它遲早會造成問題。 大多數的現代計算機作業系統都有儲存在 RAM 晶片中主記憶體和儲存在次級儲存裝置如硬碟中的虛擬記憶體，記憶體分配是動態的 每個程序根據要求獲得相應的記憶體。存取活躍的頁面檔案被轉移到主記憶體以提高存取速度；反之，存取不活躍的頁面檔案被轉移到次級儲存裝置。當一個簡單的程序消耗大量的記憶體時，它通常佔用越來越多的主記憶體，使其他程式轉到次級儲存裝置，使系統的執行效率大大降低。甚至在有記憶體洩漏的程式終止後，其他程式需要相當長的時間才能切換到主記憶體，恢復原來的執行效率。 當系統所有的記憶體全部耗完後（包括主記憶體和虛擬記憶體，在嵌入式系統中，僅有主記憶體），所有申請記憶體的操作將失敗。這通常導致程式試圖申請記憶體來終止自己，或造成分段記憶體訪問錯誤（segmentation fault）。現在有一些專門為修復這種情況而設計的程式，常用的辦法是預留一些記憶體。值得注意的是，第一個遭遇得不到記憶體問題的程式有時候並不是有記憶體洩漏的程式。 一些多工作業系統有特殊的機制來處理記憶體耗盡得情況，如隨機終止一個程序（可能會終止一些正常的程序），或終止耗用記憶體最大的程序（很有可能是引起記憶體洩漏的程序）。另一些作業系統則有記憶體分配限制，這樣可以防止任何一個程序耗用完整個系統的記憶體。這種設計的缺點是有時候某些程序確實需要較大數量的記憶體時，如一些處理影像，影片和科學計算的程序，作業系統需要重新配置。 如記憶體洩漏發生在核心，表示作業系統自身發生了問題。那些沒有完善的記憶體管理的計算機，如嵌入式系統，會因為一個長時間的記憶體洩漏而崩潰。 一些被公眾訪問的系統，如網路伺服器或路由器很容易被駭客攻擊，加入一段攻擊程式碼，而產生記憶體洩漏。 其他記憶體消耗 值得注意的是，記憶體用量持續增加不一定表明記憶體洩漏。一些應用程式會儲存越來越多資料到記憶體中（如用作快取。如果快取太大引起問題，這可能是程式設計上的錯誤，但並非是記憶體洩漏因為資料仍被使用。另一方面，程式有可能申請不合理的大量記憶體，因為程式設計者假設記憶體總是足夠執行特定的工作；例如，影像檔案處理器會在開始時閱讀影像檔案的內容並把之儲存至記憶體中，有時候由於影像檔案太大，消耗的記憶體超過了可用的記憶體導致失敗。 另一角度講，記憶體洩漏是一種特殊的程式設計錯誤，如果沒有原始碼，根據徵兆只能猜測可能有記憶體洩漏。在這種情況下，使用術語 記憶體消耗持續增加 可能更確切。 例子 C 下面是一個 C 語言的例子，在函式 f 中申請了記憶體卻沒有釋放，導致記憶體洩漏。當程式不停地重複呼叫這個有問題的函式 f，申請記憶體函式 malloc 最後會在程式沒有更多可用記憶體可以申請時產生錯誤（函式輸出為 NULL）。但是，由於函式 malloc 輸出的結果沒有加以出錯處理，因此程式會不停地嘗試申請記憶體，並且在系統有新的空閒記憶體時，被該程式佔用。注意，malloc 返回 NULL 的原因不一定是因為前述的沒有更多可用記憶體可以申請，也可能是邏輯地址空間耗盡，在 Linux 環境上測試的時候後者更容易發生。 include stdioh include stdlibh void f void void s s malloc 50 申請記憶體空間 return 內在洩漏 參見以下資料 s 指向新分配的堆空間。 當此函式返回，離開區域性變數 s 的作用域後將無法得知 s 的值， 分配的記憶體空間不能被釋放。 如要「修復」這個問題，必須想辦法釋放分配的堆空間， 也可以用 alloca 3 代替 malloc 3。 （注意：alloca 3 既不是 ANSI 函式也不是 POSIX 函式） int main void 該函式是一個死迴圈函式 while true f Malloc 函式遲早會由於記憶體洩漏而返回 NULL return 0 C 以下例子中，儲存了整數 123 的記憶體空間不能被刪除，因為地址丟失了。這些空間已無法再使用。 include iostream using namespace std int main int a new int 123 cout a endl We should write delete a here a new int 456 cout a endl delete a return 0 參閱 緩衝區溢位 參考資料 外部連結 測試記憶體洩漏 使用 MFC 除錯支援 Memory Leak Detection in C Memory Leak Detection in Embedded Systems Why doesnt my application release the memory Java FAQ Fixing Memory Leaks in KDE Memory Leaking Category 程式錯誤 Category 帶有虛擬碼示例的條目 Category 軟體異常