C++內(nèi)存管理的探討
下邊開始對C++內(nèi)存管理進(jìn)行探討:
先看一段程序:
- int main()
- {
- int i=10;
- int *j=&i;
- if(!0)
- {
- int l=20;
- int *k=&l;
- j=k;
- k=0;
- }
- cout<<*j;
- return 0;
- }
不用編譯器,大家想想執(zhí)行過之后應(yīng)該打印什么結(jié)果?我想大家的***反應(yīng)應(yīng)該是打印出一個不確定的數(shù)。理由是在if語句里,我們定義了k這個變量,在if執(zhí)行結(jié)束之后,這個變量k所占據(jù)的內(nèi)存是被系統(tǒng)收回的,于是也就造成了變量j所指的結(jié)果非常不確定。當(dāng)然,如果編譯并且執(zhí)行過后,我們發(fā)現(xiàn)事情并不是像我們想象的那樣,程序最終的打印結(jié)果是20,并不是我們期待的一個不確定的數(shù)。下面就讓我們分析一下原因吧!
我們用debug的方式來一步一步的分析,在watch的窗口下輸入里面所有的變量。
- int i=10; //i is 10 and &i is 0x0012ff7c
- int *j=&i; //*j is 10 and &j is 0x0012ff7c
- //顯然可以看出此時兩個變量指的是同一地址
- if(!0)
- {
- int l=20; //l is 20 and &l is 0x0012ff74
- /*地址0x0012ff7c—0x0012ff75被占據(jù)。要說明的是,
- 這個數(shù)值很有可能因?yàn)殡娔X硬件的不同而不同。*/
- int *k=&l; //*k is 20 and &k is 0x0012ff74
- //變量k與l指向同一地址。
- j=k; //j is 0x0012ff74 and *j is 20
- /*指針間的賦值,這個語句的意思是把k指向的地址負(fù)值給j。
- 此時這兩個變量指向的是同一個地址,都是0x0012ff74,而那
- 塊地址存放的是20,所以也就有*j是20的原因。*/
- }
- cout<<*j; //*j is 20 and j is 0x0012ff74
- /*此時同時可以看到k的地址是0x00000000,說明k這個變量
- 已經(jīng)被自動銷毀,所以地址指零。但是j所指的并不是k,而
- 是k所指的那段地址0x0012ff74,而由于此時j的生存周期還
- 沒有結(jié)束(j是在if意外定義的),所以j指向的這塊地址并
- 沒有被收回,也就保存下來20這個數(shù)了。*/
至此,我們分析完了程序的全過程的內(nèi)存分配情況,最終結(jié)果如下圖所示:
我們同時也可以在Memory里面看看這個地址的具體內(nèi)容。我們可以看到是14,這是十六進(jìn)制的數(shù),化成十進(jìn)制,正好是20。如下圖所示:
現(xiàn)在大家應(yīng)該對上面那個程序的執(zhí)行過程有一個大概地了解了吧!不過這個還不是我們想要得到的結(jié)果,我們需要的是打印一個不確定的結(jié)果。有了以上的分析,我們開始新的程序,讓他打印出我們想要的東西。
#p#
對于上面的程序,我們需要改動的是令變量j指向一個地址被釋放的位置。于是就有了下面的程序:
- int * foo()
- {
- int l=20;
- return &l;
- }
- int main()
- {
- int i=10;
- int *j=&i;
- j = foo();
- cout<<*j;
- return 0;
- }
編譯器很“聰明”,編譯后會給出一個警告。原話是“returning address of local variable or temporary”,指向的是上面程序的第四行,也就是return &l;這條語句。那句英文的意思也不用我再多解釋了,相信大家都能看得明白。
執(zhí)行的結(jié)果,在debug下,是20;在release下,結(jié)果是4198795。顯然那部分內(nèi)存被釋放掉了。這是因?yàn)樵赿ebug的程序里面,執(zhí)行完函數(shù)foo,并沒有立即釋放掉l的那個地址(目前我不清楚這句話說得是否精確)。在這個程序的release版本中,顯然程序釋放了那部分的地址,所以指向了一個不確定的數(shù)。
這里還要說一件事情,就是在***個程序當(dāng)中,無論是debug版本還是release版本。執(zhí)行完那個if語句以后,系統(tǒng)都是不會真正的把l清除掉,l只是k的一個別名。上面的程序是這樣寫的,用了*j=&i這樣一句負(fù)值語句,而別名在MSDN中的解釋與引用是相同的,所以也可以這樣理解,int i=10; int &j=i;與上面的相同。不要去想上面這些程序了,大家再看看下面這個。
- void f1( int *& j)
- {
- int l=20;
- int *k=&l;
- j=k;
- k=0;
- }
- void any_function_use_local_variables()
- {
- int a,b,c;
- a=b=c=100;
- }
- int main()
- {
- int i=10;
- int *j=&i;
- f1(j);
- cout<<*j;
- any_function_use_local_variables();
- cout<<*j;
- return 0;
- }
請大家自己編譯、執(zhí)行,看看結(jié)果是什么,然后結(jié)合上面的兩個例子,想想是為什么。下面再給大家一個小例子,可能會有助于理解內(nèi)存的概念。
程序的過程是試圖去增加i,使之超過***的整數(shù)。有一種情況是這個值被“卷回來”變成一個負(fù)數(shù),在我的機(jī)器上程序的打印結(jié)果是-2147483648,這個結(jié)果可能因?yàn)橛布牟煌煌?/p>
- int main()
- {
- int i=1;
- while(0<i) i++;
- cout<<i;
- return 0;
- }
【編輯推薦】