內存篇之堆的錯誤釋放

    在我開始寫程序時因爲擔心某些分支下忘記釋放內存導致泄漏,就想能不能保險點,多加幾次釋放,但很快發現堆內存不能重複釋放,一些錯誤釋放甚至會導致系統崩潰。這類錯誤可分幾種情況:

1)重複釋放某指針指向的內存,多數由於調用了不同層的子函數重複釋放同一內存,如:

    int* p = malloc(20);

    ……

    free (p);

    ……

    System_Free()  //此函數內再次free(p),程序員沒有注意

    有人說,釋放前加上空指針判斷就能避免這個問題。即:if(p!=null)  free(p);

    可單單這樣做並沒有效果!人們往往認爲free(p)的對象是指針p,而實際free(p)只是把指針p指向的內存釋放,並不改變指針p本身。也就是說,free不會強制清零指針pfree之後p仍指向原來內存塊,只是這塊內存已不可用而已。既然p沒有被free清零,判斷空指針的操作就不起作用。所以完整做法還要在free後加上指針清零,這樣空指針判斷纔有用,即:

    if(p!=null)

    {

      free(p);

      p = null;

    }

2)即使free後指針清0,free前做非0檢查,但如果不同指針指向同一內存,又分別被free呢,如:

    int* p1 = malloc(20);

    int* p2 = p1; //p2,p1指向同一地址

    ……;

    free( p1);

    free( p2);  //錯誤,p2所指內存已被free( p1)釋放,不能重複釋放同一塊內存。

    這種情況也是重複free同一內存,但用1)的方法沒法預防。

3)   free操作的指針不是指向堆內存:

    int a = 100;

    int* p = &a;

    free( p);  //ERROR, p don’t point to heap, and stack can’t be freed by free()

    除了malloc返回的堆內存,其他如棧內存/數據區等不能用free釋放。

4)  free操作的指針不是malloc返回的內存塊起始指針:

    int* p = malloc(20);

    p++;

    ……

    free(p); //ERROR, p doesn’t point to the start address of a memory block

    free操作的指針必須是已分配的某塊堆內存的起始指針,移動後的指針不指向內存塊起始,被free也會crash

5)  free邏輯錯誤導致野指針,多由於free時機不對,比如兩指針指向同一塊內存時:

    int* a = (int*)malloc(sizeof(int));

    int* b = a;

    free(a);

    *b = 0;      //訪問野指針

    這種類型錯誤還包括:子函數中包含釋放某指針形參所指內存的操作,而主函數不知情,在調用此子函數之後還繼續使用該內存;鏈表釋放時先釋放某節點內存,又試圖通過此節點訪問並摘除後續節點。這些都是錯誤釋放導致的野指針訪問錯誤。關於野指針,後敘。

    如果程序總在退出時crash,就要檢查是否有錯誤free

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章