擁抱智能指針,告別內存泄露

 

前言

我們都知道,當申請的內存在不用時忘記釋放,導致內存泄漏。長期來看,內存泄漏的危害是巨大的,它導致可用內存越來越少,甚至拖慢系統,最終進程可能被OOM(out of memory)機制殺死。

C與C++中的內存泄漏

在C語言中,我們用malloc申請內存,free釋放內存;在C++中,也可以使用它們,不過對於自定義類型,常常會使用new申請,delete來釋放。它們都有同樣的問題,一旦申請了,但是忘了釋放,就會造成內存泄漏,而已經釋放了又仍然去訪問它,則造成更加直接的嚴重後果。
一個簡單的例子:

//main.c
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    char *p = NULL;
    int i = 0;
    while(1)
    {
        p = malloc(1024);
        snprintf(p,1024,"%6d\n",i);
        i++;
    }
    return 0;
}

這是一個很明顯的內存泄漏的例子,malloc申請內存後,從來沒有釋放過,編譯運行一段時間後,可能被直接被kill。有興趣也可以通過top命令觀察其內存變化。

也就是說,C/C++中自己用的內存,要自己記得還回去。

而即便有的時候,你記得delete了,但是中間出現異常,導致delete沒法執行,同樣導致內存泄漏,例如:

Test test = new Test();
/*do some thing*/
delete test;

如果在執行某些操作的時候拋出異常,就可能導致delete無法執行到,從而導致內存泄漏。

Java程序員的幸福

Java程序運行在Java虛擬機上,它有一套垃圾回收(GC)機制,它會定期地回收那些不再被使用的內存,可以有效的防止內存泄露(但不能避免,Java中同樣存在內存泄漏)。

但是另外一方面,由於垃圾回收並不是立即的,時機也不是確定的,同時回收機制本身可能比較複雜,會佔用空間和時間開銷,畢竟C/C++注重效率。

智能指針

爲了既能最大程度的避免內存泄漏又能兼顧效率,C++11標準引入了智能指針shared_ptr和unique_ptr。

本文不詳細介紹它們的用法,本文旨在通俗地說明它的場景,幫助你理解。

shared_ptr

通常來說,動態申請了一片內存之後,可能會在多個地方會用到,對於裸指針,你需要自己記住在什麼地方釋放內存,不能在有別的地方還在使用的時候,你就釋放,也不能忘記釋放。如果是這樣,爲什麼不在有人用的時候,就增加引用計數,而不用的時候(離開作用域或者生命週期外)就較少引用計數呢,如果引用計數爲0,則自動釋放內存。

舉個通俗的例子,假設一個房間裏有自動感應燈光。有人在的時候,燈亮了(申請使用內存),再來一個人,這個燈還是亮着,人數增加,而這兩個人走掉的時候,房間空了,感應不到人(引用計數爲0)的時候,燈就可以自動滅了(自動釋放內存),這樣也就最大程度地利用了燈光。

不過它的實現要考慮的因素很多,例如如何原子地增加引用計數。所以它在一定程度上比裸指針開銷要大。

unique_ptr

與shared_ptr不同,unique_ptr專屬某個對象資源。也就是說,如果某個對象有一個專屬管理,它不能被複制,那麼當這個專屬管理不再使用的時候,就可以自動釋放內存了。

同樣一個通俗的例子,我們現在在很多洗手間都可以看到自動感應的水龍頭,一個水龍頭通常只供一個人使用(申請並佔用資源),而當這個人離開的時候,水龍頭自動關閉(自動釋放內存)。

而對於老式的水龍頭,一旦忘了關了(好像一般也不會忘),就會一直浪費水。

weak_ptr

還有一種情況,對於某些對象,如它可能作爲緩存。它有的時候,我就用一下,沒有的時候就不用,也不負責去管理資源的釋放資源,豈不美哉?

總結

C++新引入的智能指針在使用得當的情況下,可告別內存泄漏。具體用法,我們在後面的文章進行介紹。

推薦閱讀:

​首發:公衆號【編程珠璣】

作者:守望先生

ID:shouwangxiansheng

關注公衆號【編程珠璣】,獲取更多Linux/C/C++/算法/計算機基礎/工具等原創技術文章。後臺免費獲取經典電子書和視頻資源

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