1. 程式人生 > >淺談記憶體洩漏,野指標,記憶體申請

淺談記憶體洩漏,野指標,記憶體申請

拿到quiz好難過,記憶體洩漏一個Vector一個Array秀的我頭疼。

記憶體洩漏

百度百科上的定義:記憶體洩漏(Memory Leak)是指程式中己動態分配的堆記憶體由於某種原因程式未釋放或無法釋放,造成系統記憶體的浪費,導致程式執行速度減慢甚至系統崩潰等嚴重後果。

一看定義,坑好像更多了,動態分配,堆記憶體是什麼?
某種原因包含哪種原因?
未釋放我能理解,無法釋放是什麼時候
看後果很嚴重,執行速度減慢!系統崩潰!那麼記憶體究竟為什麼這麼強??

危害舉了一個例子,比如伺服器應用軟體,需要長時間的執行,如果沒有有效的記憶體管理,每次處理客戶發來的資訊都沒有釋放記憶體,產生記憶體洩漏,那麼這樣就會影響伺服器的效能,引起整個系統的崩潰。

它是拿C語言做的例子,看完危害,我們再來看看百度百科的洩露原因:

從變數存在的時間來分類,分為靜態儲存變數和動態儲存變數
靜態儲存變數:程式執行期間分配了固定儲存空間的變數
動態儲存變數:程式執行期間根據實際需要動態地分配儲存空間的變數。
所以它們的區別就在於,一個是一開始固定分配好了,一個是根據實際需要,你要多少我分配給你多少。感覺動態分配很棒,他怎麼實現的呢?

記憶體中供使用者使用的區域:程式儲存區,靜態儲存區,動態儲存區
程式用的資料呆在靜態儲存區和動態儲存區
靜態儲存區資料在程式的開始就分配好記憶體區,在整個程式執行過程中它們所佔的儲存單元是固定的,在程式結束時就釋放(真省心啊),因此靜態儲存區資料一般為全域性變數。全域性變數的坑等下補,我們把全域性變數和靜態變數,靜態儲存區的關係捋一下

動態儲存區資料則是在程式執行過程中根據需要動態分配和動態釋放的儲存單元(分配了要釋放呀!)動態儲存區資料有三類函式形參變數(三類函式時哪三類)、區域性變數和函式呼叫時的現場保護與返回地址。現場保護又是什麼。。

程式中動態分配的儲存空間,在程式執行完畢後需要進行釋放。
沒有釋放動態分配的儲存空間而造成記憶體洩漏,是使用動態儲存變數的主要問題。
一般情況下,開發人員使用系統提供的記憶體管理基本函式,如malloc、recalloc、calloc、free等,完成動態儲存變數儲存空間的分配和釋放。

無論是C還是C++程式,執行時候的變數主要有三種分配方式:堆分配、棧分配、全域性和靜態記憶體分配。記憶體洩漏主要是發生在堆記憶體分配方式中,即“配置了記憶體後,所有指向該記憶體的指標都遺失了”,若缺乏語言這樣的垃圾回收機制,這樣的記憶體片就無法歸還系統。

總結一下,記憶體洩露,是指程式在申請記憶體後(申請這個用詞還是形象呀),無法釋放或未釋放已申請的記憶體空間,一次記憶體洩露危害可以忽略,但記憶體洩露堆積後果很嚴重,無論多少記憶體,遲早會被佔光。
記憶體洩漏是指你向系統申請分配記憶體進行使用(new),可是使用完了以後卻不歸還(delete),結果你申請到的那塊記憶體你自己也不能再訪問(也許你把它的地址給弄丟了),而系統也不能再次將它分配給需要的程式。
舉個例子,就像你申請把一個物品裝在保險櫃裡,你用它的時候給它分配了一個保險櫃,可是用完了沒有把你的保險櫃收回,你走就走了,可是記不了保險櫃的地址,再也找不到這個保險櫃了,你覺得沒問題,我有好多保險櫃呢,可是如果這個問題一直髮生,你的保險櫃會全部用光的。
哈哈哈,對C++來說,記憶體洩漏就是new出來的物件沒有delete,俗稱野指標。你這個沒有物件的野指標哈哈哈哈哈。這句話怎麼理解呢,我決定去看看野指標的定義!

野指標

百度百科上,野指標的定義:野指標指向一個已刪除的物件或未申請訪問受限記憶體區域的指標。與空指標不同,野指標無法通過簡單地判斷是否為 NULL避免,而只能通過養成良好的程式設計習慣來盡力減少。對野指標進行操作很容易造成程式錯誤。需對指標進行初始化

引用百度百科上的野指標介紹,講的還是蠻清楚的

為什麼會出現野指標:

  1. 指標變數未初始化
    任何指標變數剛被建立時不會自動成為NULL指標,它的預設值是隨機的,它會亂指一氣。所以,指標變數在建立的同時應當被初始化,要麼將指標設定為NULL,要麼讓它指向合法的記憶體(int *p = &a, 這就是指向合法的記憶體了。)。如果沒有初始化,編譯器會報錯“ ‘point’ may be uninitializedin the function ”。
  2. 指標釋放後未置空
    有時指標在free或delete後未賦值 NULL,便會使人以為是合法的。別看free和delete的名字(尤其是delete),它們只是把指標所指的記憶體給釋放掉,但並沒有把指標本身幹掉。此時指標指向的就是“垃圾”記憶體。釋放後的指標應立即將指標置為NULL,防止產生“野指標”。
    看到2我明白了,上面說的:對C++來說,記憶體洩漏就是new出來的物件沒有delete,俗稱野指標。我覺得不太準確,記憶體洩漏說的是為物件申請的記憶體未被釋放,野指標說的是指向已被刪除的或者未申請受限訪問記憶體的指標。怎麼能說記憶體洩漏俗稱野指標呢?這就像說保險櫃沒清理(記憶體洩漏)和指向特殊保險櫃的指示牌(野指標)是一回事一樣。
    3.指標操作超越變數作用域
    就是在你超過作用域後,記憶體已經釋放,這時指向那個被釋放的記憶體的指標就是野指標,你卻還呼叫,這樣不好。這個例子就是原因
class A {
public:
  void Func(void){ cout << “Func of class A” << endl; }
};
class B {
public:
  A *p;
  void Test(void) {
    A a;
    p = &a; // 注意 的生命期 ,只在這個函式Test中,而不是整個class B
  }
  void Test1() {
  p->Func(); // p 是“野指標”
  }
};

申請記憶體是怎麼一回事?

在C++中,進行堆記憶體管理的是new和delete
對應C中的malloc和free
但是 malloc 和 free 是函式,而new 和 delete 是運算子
這篇部落格講C++和C的記憶體管理挺不錯的

總結一下,
我們談到了記憶體洩漏是什麼,野指標是什麼及它的成因
C++和C的記憶體管理

其實留下了一堆坑,比如堆記憶體,還有需要單獨開一篇文章來說C和C++的記憶體管理,我認為這是這兩個程式語言比較重要的特性。