繁体   English   中英

可可64位二进制文​​件泄漏内存? (释放NSData不释放内存)

[英]cocoa 64bit binaries leak memory? (releasing NSData does not free memory)

我一直在玩我的应用程序的不同版本,似乎有些奇怪的事情要发生:

我的应用程序有5mb空闲的足迹。 当保存上传文件大小的文件时。 上传后,应释放保留的内存。 现在构建中存在差异(gc =垃圾收集器):

  • 32位i386 no-GC:立即释放所有内存。
  • 32位i386 GC:几乎所有内存都立即被释放。 其余的一段时间后。
  • 64位x86_64 no-GC:释放最小内存。 像10%
  • 64位x86_64 GC:根本没有内存被释放。 记忆保持数小时。 (活动星期一)

我正在使用LLVM和CLANG。 我一直在运行今天的仪器,并检查泄漏/僵尸/等。 一切似乎都很干净。 (该应用程序相当简单。)

这种行为有解释吗?


更新:

那是一些奇怪的东西。 我把问题归结为:

我将一个20mb的文件加载到NSData中并释放它。 我这样做没有启用任何垃圾收集。 代码是:

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigshit"];
[bla release];

当我为i386 32bit构建时,20mb被分配并释放。 当我将构建切换到64位x86_64时,版本什么都不做。 20mb住宿分配。

上部图片32位以下64 http://kttns.org/zguxn

两个应用程序之间没有区别,除了上面的一个是32位而下面的64位。 没有GC运行。 (启用GC后,会出现同样的问题。)


更新2:

当我从头开始创建一个新的cocoa应用程序时,可以观察到相同的行为,只有applicationDidFinishLaunching中的高位代码: 在64位模式下,内存不会被释放。 i386按预期工作。

NSString而不是NSData出现同样的问题。 当我启动64位内核时,它也会出现。 (启动时保持64位。)

操作系统是10.6.0

首先,使用Instrument的Object Graph仪器验证内存不再被认为正在使用中; 在某处没有保留计数或强引用。

如果它不再使用,那么内存就会因为你没有达到收集器关心的阈值而坚持下去。

但是,这句话:

64位x86_64 no-GC:释放最小内存。 像10%

让我警惕。 具体来说,如果您的代码设计为在非GC中工作 - 使用retain / release - 那么(a)您有内存泄漏,如果使用CFRetain或某种全局缓存,可能会影响GC或(b)你没有使用正确的工具来判断你是否有内存泄漏。

那么,你如何确定你在泄漏记忆?

更新 ; 您正在使用活动监视器来监视进程的RSIZE / VSIZE。 除了“我的流程随着时间的推移而增长”之外,这实际上并没有告诉你什么有用。

更可能(我没有看过源代码),这段代码:

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigpoop"];

将导致20MB文件为mmap()进入该进程。 根本没有涉及malloc()样式分配。 相反,操作系统将20MB的连续地址空间交给您的进程,并将文件的内容映射到其中。 当您阅读NSData的内容时,它会在文件中出现页面错误。

释放bla ,映射将被销毁。 但这并不意味着VM子系统会将应用程序的地址空间减少20MB。

所以,你正在烧掉一堆地址空间,而不是实际的内存。 由于您的进程是64位,因此地址空间几乎是无限资源,使用地址的成本非常低,因此操作系统以这种方式实现的原因。

即没有泄漏,你的应用程序表现正常,GC或没有。

这是一个常见的误解,因此,这个问题很明显。

垃圾收集器不一定立即释放内存。

在Objective-C垃圾收集器的情况下,您可以向Cocoa的垃圾收集器对象发送一个collectIfNeeded消息,以表明现在可能是进行一些收集的好时机,或者collectExhaustively按顺序收集以命令它立即开始收集任何和所有垃圾(但是即使这是可以中断的)。 查看文档

我在iPhoneOS 3.2中有一个非常类似的问题,我真的不认为内存正在被回收 - 我最终会触发内存警告。 我忽略了自己的错误的可能性很小,但我已经非常彻底了。

我使用NSKeyedUnarchiver的unarchiveObjectWithFile:来加载包含单个大型NSData和另一个小得多的对象的自定义对象。 我的自定义对象中的dealloc方法被调用,NSData对象被释放,其retainCount == 1就在之前。 物理内存不会减少任何数量,更不用说NSData大小的一小部分,并且可靠地生成重复内存警告:我已经测试,直到我实际收到2级警告。 =(

发布前:

(gdb)p(int)[(NSData *)pastItsWelcomeData retainCount]
1美元= 1

发布后:

(gdb)p(int)[(NSData *)pastItsWelcomeData retainCount]
目标不响应此消息选择器。

暂无
暂无

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

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