简体   繁体   English

Objective-C内存问题(iPhone)

[英]Objective-C memory issue (iPhone)

I'm somewhat confused by the following behavior I'm seeing within an Xcode project compiled for the iPhone simulator (or device): 我在为iPhone模拟器(或设备)编译的Xcode项目中看到的以下行为让我感到困惑:

NSString *test = [[NSString alloc] initWithCString:"foo"];

NSLog(@"test retain count = %d", [test retainCount]); // prints 1

[test release];

NSLog(@"test retain count = %d", [test retainCount]); // also prints 1 instead of 0

However, any further attempts to access 'test' result in a crash of the Xcode enviroinment, whether it be another [test retainCount] NSLog statement or otherwise (even if only to check if test is equal to nil). 但是,任何进一步尝试访问'test'都会导致Xcode环境崩溃,无论是另一个[test retainCount] NSLog语句还是其他(即使只检查test是否等于nil)。

Thoughts? 思考? Compiled within a simple View based test project...code exists within project's applicationDidFinishLaunching method. 在一个简单的基于视图的测试项目中编译...代码存在于项目的applicationDidFinishLaunching方法中。

Clarification -- I know NOT to do the above in practice. 澄清 - 我知道不要在实践中做上述事情。 This was just a test to see why in some debugging cases a retain count of 1 wasn't actually reflecting the real state of an object. 这只是一个测试,看看为什么在某些调试情况下,保留计数为1实际上并不反映对象的实际状态。 Thanks for your responses. 谢谢你的回复。 This was just a test stub to see why I was seeing certain behavior in a few cases. 这只是一个测试存根,看看为什么我在一些情况下看到某些行为。 What I'm really trying to do is track down a very small memory leak (0.06MB) that is consistently being created whenever I destroy/recreate a custom view. 我真正想要做的是追踪每当我销毁/重新创建自定义视图时始终创建的非常小的内存泄漏(0.06MB)。

Retain counts are a debugging aid and can be misleading based on what Cocoa may be doing behind the scenes. 保留计数是一种调试辅助工具,根据Cocoa在幕后可能做的事情可能会产生误导。 This is particularly true with string literals where the data is permanently available and is never really deleted. 对于字符串文字尤其如此,其中数据永久可用且永远不会被真正删除。

Concentrate of ensuring your code follows the Cocoa memory management rules with respect to object ownership. 集中精力确保您的代码遵循关于对象所有权的Cocoa内存管理规则 Where necessary, use Instruments to check for actual memory leaks. 必要时,使用Instruments检查实际的内存泄漏。

要调用retainCounttest它已被释放,并可能释放 ,所以肯定结果是不可靠的,别说你不应该发送dealloced对象的任何消息。

Don't rely on retain counts...the framework may be retaining stuff on its own. 不要依赖保留计数......框架可能会保留自己的东西。

Instead, rely on the rules of memory management for objective-C. 相反,依赖于Objective-C的内存管理规则。 If you alloc, init, or new something, you own it and are responsible for releasing it. 如果你分配,初始化或新的东西,你拥有它并负责释放它。 If you didn't, you aren't. 如果你没有,你就不是。

don't rely on the retain count; 不要依赖保留计数; instead, make sure that you're balancing retains and releases. 相反,请确保平衡保留和释放。 Here are some links on Cocoa (Touch) memory management: http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html 以下是Cocoa(Touch)内存管理的一些链接: http//iamleeg.blogspot.com/2008/12/cocoa-memory-management.html

When you send that release , the string is dealloced — it has no other owners retaining it. 当您发送该release ,该字符串将被解除分配 - 它没有其他所有者保留它。 Sending further messages to it (including retainCount ) is an error and won't return anything meaningful. 向它发送更多消息(包括retainCount )是一个错误,不会返回任何有意义的内容。

And as others have pointed out, don't rely on retain counts to be particularly useful. 正如其他人所指出的那样,不要依赖保留计数特别有用。 They're a piece of the picture you can look at, but they're often misleading. 它们是你可以看到的一幅画面,但它们往往会产生误导。 For example, autoreleases don't show up in the retain count, sometimes objects are retained extra times for caching purposes, etc. In this particular case, though, you're not sending the message to a valid object at all, so you're lucky to get back an answer rather than a crash. 例如,自动释放不会显示在保留计数中,有时为了缓存目的而保留额外的对象等等。但是,在这种特殊情况下,您根本不会将消息发送到有效对象,所以你'很幸运能找到答案而不是崩溃。

You should read Apple's memory management guide if you're unclear on any of this. 如果你不清楚这些,你应该阅读Apple的内存管理指南 It's not too complicated and absolutely essential for programming Cocoa. 它对于编写Cocoa来说并不是太复杂和绝对必要。

One trick to improve the code shown above would be to use the 'set to nil' convention. 改进上面显示的代码的一个技巧是使用'set to nil'约定。

EG: 例如:

NSString *test = [[NSString alloc] initWithCString:"foo"]; NSString * test = [[NSString alloc] initWithCString:“foo”];

NSLog(@"test retain count = %d", [test retainCount]); NSLog(@“test retain count =%d”,[test retainCount]); // prints 1 //打印1

[test release]; [测试发布]; test = nil; test =零; // set to nil, as I have released the pointer, I should no longer use it. //设置为nil,因为我已经释放指针,我不应再使用它了。

NSLog(@"test retain count = %d, test foobarpro = %d", [test retainCount], [test foobarPro]); NSLog(@“测试保留计数=%d,测试foobarpro =%d”,[测试retainCount],[测试foobarPro]); // will now print 0 and 0 - because any objective-c call on a nil object returns 0 (and will not crash) //现在将打印0和0 - 因为对nil对象的任何objective-c调用都返回0(并且不会崩溃)

By setting a pointer to zero after you release it, you future proof your code a little: Someone coming along later and editing code 10 lines below can accidentally use 'test' with likely no ill effects (or an obvious crash). 通过在释放后将指针设置为零,您将来可以稍微证明您的代码:稍后出现并编辑下面10行的代码可能会意外地使用“测试”,可能没有任何不良影响(或明显的崩溃)。 I even set pointers to nil in dealloc calls, as some of the hardest debugging tasks happen when non - nil 'bad' pointers are used in destruction. 我甚至在dealloc调用中设置指向nil的指针,因为一些最难的调试任务发生在非破坏的'坏'指针被用于破坏时。

Also you can debug with zombies to look for cases where you use pointers like your invalid test. 您也可以使用僵尸进行调试,以查找使用无效测试等指针的情况。

--Tom --Tom

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM