作者HuangJC (吹笛牧童)
看板MacDev
標題Re: [問題] 簡單的程式就有 memory leak 了
時間Wed Apr 16 20:12:36 2014
來看看 MFC 怎麼實作 CString
MFC 在 CString 也是用一種 ref count 機制
而且 MFC 完全公開 source code,也沒擴充保留字
有人還把它給拷了,送到沒 MFC 但有 C++ 的地方去用
網路上好像找得到,叫 CxString (至少敝公司有維護一套)
CString F1()
{
CString str = "xxx"; // 產生一個字串, ref = 1
return str; // 使用 RC 的書怎麼教的? 書上說 str 在離開堆疊時就消失了,
// 所以要 retain
}
那 CString 怎麼做呢?
以下是我理解的看法
(書上不是這樣教的,總之 source code 公開,去 trace 一下可以印證我的看法)
它把函式的輸出結果也當一個變數
你可以想像有一個變數叫做
CString ret;
所以在 F1() 的最後一行, return str;
其實是執行了 ret = str;
然後外面 caller 端再去接這個 ret
比如 caller 端如果是寫
CString str2 = F1();
那這裏就等於有 str2 = ret; //這個 ret 是剛剛 F1 函式的傳回值
然後 ret 就釋放了 (寫在 CString 的 destructor, ~CString)
如果沒人去接,也就是單純呼叫 F1()
那 ret 也會先接,然後再釋放
總之 ref count 的計算是完美的
然後在 ref count 為 0 時, CString 會把內部物件真的釋放掉
這一切,不必 precompiler 特別幫忙,不必擴充 C++
它是由標準 C++ 組成的 MFC 完成的,可以轉移到沒有 MFC 的 C++ compiler 去
若說有什麼缺點.. 有
那就是只有 CString 寫這麼好用
如果我想自己寫一個 class, 就不會自動被賦與這麼漂亮的機制,要 coding 一堆東西
這其中包括要去覆寫 operator, constructor, destructor 等等
然後還有很煩的,比如 operator + 這個 function, 和 const operator + 是不一樣的
(就是多了個 const 而已啊..)
要各別覆寫,即使內部的 code 其實是一模一樣
operator = 和 constructor 可能是不一樣的
差異在 ref count 的計算方式
也就是說,想打造一個自己的 class 和 CString 一樣好用,要寫很多 code
比較簡單的方法是 template,不過我和它不熟
聽說用 template 可以很快的產生自己的 auto ref count style class.....
在看到 Obj C 的 ARC 時,我以為它是完美的把這套搬進 Compiler
所以我就這麼寫
- (NSString*)F1
{
NSString* str = @"xxx";
return str;
}
外面 caller 端是
NSString* str2 = [self F1];
以上對 ref 的討論會一模一樣嗎? 也就是函式執行結束時,等於有一個中介變數 ret
如果有這種東西,那其實是用不到 autorelease 才對
因為 compiler 幫我們加了 retain & release
return str; //這裏要往外傳,所以加一個 retain
[self F1]; //這裏是 caller 端的角度,已經傳出來了,所以加一個 release
NString* str2 = [self F1]; // 這種有 str2 來接,所以會先幫 str2 加一個 retain,
再幫函式的傳回值加一個 release, 兩個剛好對消, ref count 不變
如果一切像我想的這麼完美,那應該用不到 autorelease
我是這麼希望的啦
----
然後前面我說,我知道我的程式沒有 memory leak, 這是我長久以來的筆誤
其實是記憶體佔用但沒釋放,不知該叫什麼
嗯,我找到接近的 ~^_^~
http://blog.eddie.com.tw/2010/11/22/memory-management-in-objective-c/
> 又或許你會覺得這樣一顆小物件是能佔多少記憶體。這種東西積沙成塔的,
> 你借了記憶體來用卻沒還回去,久了可能就會造成”漏水”(memory leaking)的情況
看,它沒犯我的錯誤,它不是說"這叫 memory leaking"
它是說,這可能會"造成" memory leaking
(照我上一篇的問題,這哪有 leak? 你一直有 pointer 指著它,它就不是 leak)
我現在還是為這樣的溝通困擾著
而且如果 arc 這機制是 ref count 為 0 時就呼叫 dealloc
那我也搞不懂為什麼會有 leak
--
活動/美食計劃
蘭嶼 魚白 勝興車站 星月天空 武陵 草嶺古道
嘉義阿里山小火車 保齡球 司馬庫斯
手包水餃 日月潭纜車 合歡攻頂 馬祖
鹽山 南庄 澎湖 溪頭/松林町 南投天梯
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.251.197.63
※ 文章網址: http://webptt.com/m.aspx?n=bbs/MacDev/M.1397650361.A.2BE.html
1F:→ uranusjr:安安, 請問知道什麼叫 stack allocation 嗎? 04/16 21:15
不是很清楚
我知道一些,但有人叫我不要硬套
所以是否請你完整說明,我來對照一下
2F:推 timTan:CString 不做 Reference Counting 04/16 22:19
可以去看一下它裏面怎麼做的
如果有二十個字串,當初都從同一個地方拷貝出來
那要二十倍的記憶體嗎?
MFC 有想到要節省這個記憶體,它安排了它的方式
如果你說那不是 ref counting,我也不能說你錯
因為它'沒有完全一樣'
但它有它的一套,也很完整
3F:推 Blueshiva:1.早就叫你不要老是不管ObjC怎麼做,老是拿其他東西來 04/17 01:05
4F:→ Blueshiva:"以為"硬套 2.@"ooxx"這種NSString是特例,拿這來看看不 04/17 01:07
5F:→ Blueshiva:懂的 04/17 01:08
謝謝指教
6F:→ atst2:rc是一種ownership policy, 編譯器只管你有沒有符合rc規範, 04/17 01:36
7F:→ atst2:不會去猜測你的程式為什麼會留著物件不用. 04/17 01:37
也不能說猜測啦,以我舉的 CString 來說
它是很明確而且很有效很完整的處理了指標的 ref counting
它沒特別擴充 C++ 啊
而我們知道 Obj C++ 是 C++ 的超集
也就是說,至少如果我把這套搬進 compiler, 是絕對可行的邏輯;夠完整
我問的就是: Obj C 用的方法,有哪裏不一樣嗎?
不過我現在知道,我可以用個指令去讀出目前的 ref counting 為多少
這多少對驗證 compiler 的行為有幫助;不然我都不知它哪裏做的和我預期不同了
8F:→ atst2:另外,要用Instrument就弄清楚工具真正的用法及意義,不要自 04/17 01:40
9F:→ atst2:己單看圖表就猜測。以你附的圖來說,記憶體升高又降低,就代 04/17 01:41
10F:→ atst2:表有用到也有釋放, Allocation保持一定的記憶體是原本程式 04/17 01:42
11F:→ atst2:跑起來就需要的,與Leak完全無關。 04/17 01:43
應該不是說 leak,而是說'佔用而沒釋放';我前面說過了,這是我長年來的筆誤
我發現我同事和我一樣會誤用這個名詞,所以我們溝通還沒問題
現在的狀況是,程式不是一個人寫的,是大家寫的
所以我們見到一塊記憶體沒釋放(並不是 leak),就會互推責任
這狀況很糟啊,所以不是很計較記憶體捨不得用
而是,即使連一個 byte 都希望不要多出來
這樣才劃得清責任
我的模組完成了,才能交給別人 (假設我的模組是較核心,被呼叫的副程式)
用得記憶體雖然少,但來回幾次就愈用愈多
就算只有2K,3K,也難保不會被人說'抓到了,人是你殺的'
如果說因為某些指令,內部是用 auto release 寫的
所以必需到 @autorelease 時才能釋放
那最好我就加這個東西,釋放完才把副程式交給同事
這樣完全厘清,對團隊合作會比較好
12F:→ atst2:rc這東西在c++也有,去看看STL smart_ptr是怎麼回事,去讀一下 04/17 01:44
13F:→ atst2:Modern C++ Design(C++設計新思維), Boost, Google的資料也 04/17 01:45
14F:→ atst2:很多... 04/17 01:46
在 COM 裏面我也見過一次
不過這些都別提了
不是老有人叫我不要拿以前學過的東西來跘住自己嘛
15F:推 Blueshiva:基本上,如果你自己都已經能找到高見龍的文章來看,那應 04/17 02:41
16F:→ Blueshiva:該就是個會用Google的人,看你能舉那麼多MFC的東西,應 04/17 02:41
17F:→ Blueshiva:該不會是個程式新手。那為什麼會搞成現在這種局面呢?就 04/17 02:42
18F:→ Blueshiva:是"倚老賣老"這四個字造成的,老是以為能拿以前對事物的 04/17 02:43
19F:→ Blueshiva:理解來硬套,然後自己覺得怪怪的,就開始用些更旁門左道 04/17 02:44
20F:→ Blueshiva:的方法來硬幹。總歸一句,就是根基不穩,然後照你這種個 04/17 02:45
21F:→ Blueshiva:性,我覺得網路上這種一篇一篇的文章給你看了大概也不會 04/17 02:45
22F:→ Blueshiva:有幫助。要我給建議的話,你還是放下無謂的堅持,買本書 04/17 02:46
23F:→ Blueshiva:來看吧。 04/17 02:46
謝謝指教
24F:推 abcdefghi:Apple一直在持續改善ObjC, 從語言本身到compiler, 所以 04/17 04:23
25F:→ abcdefghi:有些資訊比較混亂, 真的要深入看, 還是得仔細看官方的技 04/17 04:24
26F:→ abcdefghi:術文件, 再配上其他人的解說, stackoverflow是最好的地 04/17 04:25
27F:→ abcdefghi:方, 不過keyword可能要花點心思. 04/17 04:26
28F:→ HuangJC:的確... 其實我有時是從兩三個互相對立的答案中挑一個 04/17 04:27
29F:→ HuangJC:就好像這次,有人說'會馬上釋放',也有人說'不會' 04/17 04:28
30F:→ HuangJC:我覺得大家貢獻自己想法來討論很好啊 04/17 04:28
31F:→ HuangJC:奇怪的是我提 MFC 來對照,突然被說'別提以前的經驗了' 04/17 04:28
32F:→ HuangJC:那 ref counting 我讀的書,就只有簡短幾句話 04/17 04:29
33F:→ HuangJC:"它是 precompiler 自動幫你插入 retain/release" 04/17 04:29
這樣說吧,其實 C 的 precompiler 是有獨立程式可以看結果的
*.c 可以 compile 成 *.i
這 *.i 很繁鎖,但也有助於厘清問題,看 precompiler 做的和你想的有沒有一樣
如果說 ARC 就是 precompiler 幫忙插入 retain/release
那有沒有這樣一支程式把 *.m 轉成 *.i
如果有,我也不用再猜,就可以靜靜的實驗一些東西
不然老說看書,書上寫得少啊
手上兩本書都在教沒有 ARC 的版本
34F:→ HuangJC:所以我拿 MFC 下學到它何時加一,何時減一,不也是個討論的 04/17 04:31
35F:→ HuangJC:起點.. 04/17 04:31
36F:→ HuangJC:我一個同事說:看書太慢,google 比較快 04/17 04:32
37F:→ HuangJC:主管說:別上網問了,我不信會寫的人會在網路上玩 04/17 04:33
38F:推 Blueshiva:1. 沒人說你不能用以前的經驗來理解現在的東西,但是注 04/17 08:16
39F:→ Blueshiva:意,是"理解",不是"硬套"。其他地方的經驗只是"輔助", 04/17 08:17
40F:→ Blueshiva:而不是像你現在這樣"MFC是怎樣,ObjC就應該是怎樣" 04/17 08:18
要一句句講贏你不難,但吵贏後我反而會變輸家
我只回應這句
> "MFC是怎樣,ObjC就應該是怎樣"
我是這樣表達的嗎? 如果你看成這意思,那我道歉
我的意思是"我理解 MFC 是這樣的,請問 Obj C 是怎麼做的"
所以我對你只有一個請求:我知道自己的作業自己做
如果你認為套別種語言的經驗不好的話,請你不要再回應
因為有其他人是可以接受這種經驗的
學生時有一次在餐廳,同學間討論問題,我就坐在旁邊
就該領域,很明顯我領先他們,但因為太常問我了,所以連飯都沒空吃
同學也很體諒,就沒再問我了
旁聽時我感覺講解的同學錯了,但我並沒去糾正
因為如果要糾正,一定是落落長一大篇
但那多少是滿足一種潔癖而已
用另一種講法來翻譯同學間的對話,大概像這樣
甲:地球是什麼型狀的?
乙:地球是圓型的
我心中OS:才怪,地球是橢圓型的
看出問題沒有?我有必要糾正到這境界嗎?
而就算我說地球是橢圓型的,就沒錯誤了嗎?
如果我這樣插嘴:
才不是圓型的,至於什麼型狀我就不說了,你不會去看置底啊
請問有什麼幫助? 要放話就要完整
不然就讓其他人去發揮
教地球是圓型的同學也是熱心,也節省了我的時間
我不懂這樣是有什麼不對了
41F:→ Blueshiva:2.Google是針對"遇到特定問題"的時候會比較快,但是現在 04/17 08:19
42F:→ Blueshiva:看來,你,或者你們整個team,都不是能夠觸類旁通,也都 04/17 08:19
43F:→ Blueshiva:沒有基礎,這樣用Google硬幹,只是連關鍵字都不知道怎麼 04/17 08:19
44F:→ Blueshiva:下而已。整串下來,也不止我一個跟你講了,不打基礎,那 04/17 08:20
45F:→ Blueshiva:就去找個懂的人加入你們team。你主管豬頭覺得東西都一樣 04/17 08:20
46F:→ Blueshiva:要你們只學過英文卻連あいうえお都搞不清楚的去翻譯阪上 04/17 08:23
47F:→ Blueshiva:之雲,不代表你就只能把每段話丟到Google翻譯剪下貼上交 04/17 08:24
48F:→ Blueshiva:差了事 (當然如果你本來就是這種個性...那就算了) 04/17 08:24
49F:→ Blueshiva:3.會寫的人不會在網路上玩?自己google一下zonble、高見 04/17 08:25
50F:→ Blueshiva:龍、xdite,看他們夠不夠格稱得上"會寫",再看看他們有 04/17 08:26
51F:→ Blueshiva:沒有在網路上"玩" 04/17 08:26
52F:→ Blueshiva:4.找書?沒看置底文? 04/17 08:26
53F:→ Blueshiva:5.最後回應一下為什麼書都在教沒有ARC的版本,因為ARC就 04/17 08:28
54F:→ Blueshiva:只是自動加入retain/release,所以如果你真的要管好記憶 04/17 08:28
因為 MFC 只是自動加入 add ref count / remove ref count
所以也有助於理解 ARC
看,一樣說得通
要說不通就指出來: ARC 的 ref count 和 MFC 的做法不同
要不然,有用 ref count 的語言,其實也不只 C++/MFC
多得是觸類旁通的機會,做法也大同小異
我相信大部份人都因為過往的經驗而縮短了學習的時間
55F:→ Blueshiva:體,了解沒有ARC的時候是怎麼運作的還是有相當大的幫助 04/17 08:28
56F:→ Blueshiva:或者這樣講吧,把手動管理學起來,轉用ARC只是一篇簡單 04/17 08:29
57F:→ Blueshiva:教學的事 04/17 08:29
我知道,所以我不可以發一篇 MFC 的作法來比較嗎?
我發了後,就是指責 Obj C '怎麼不用這種做法'嗎?
雖然我可以承認自己溝通有問題
但長此以往,再裝就不像了
除了謝謝指教,我還能說什麼?
58F:→ howdiun:instruments裡面可以看各物件占用的記憶體 04/17 11:22
59F:→ howdiun:記憶體吃太多,應該找出吃記憶體的物件 04/17 11:24
60F:→ howdiun:加一減一那是知識,不是拿來實務用的,不知道也可以寫 04/17 11:25
剛和同事討論,同事還是用 memory leak 這個字眼
我稍微解釋一下後,他回我:
反正還不是一樣,都不正常
好啦,反正來回於兩個用字不同的群組間,就是要有一個人擔任翻譯
所以同事說 memory leak 時,我就自動翻譯成'記憶體佔用'
※ 編輯: HuangJC (60.251.197.63), 04/17/2014 15:12:15