作者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/cn.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