问题 如何避免GC环境中自定义NSURLProtocol中_NSCFURLProtocolBridge中的引用计数下溢


基础是我有一个习惯 NSURLProtocol。在 startLoading[self client] 是类型:

<_NSCFURLProtocolBridge> {NSURLProtocol, CFURLProtocol}

问题是在垃圾收集环境中运行。因为我正在写一个屏幕保护程序,所以我不得不把它垃圾收集起来。但是,_NSCFURLProtocolBridge协议似乎总是抛出:

malloc: reference count underflow for (memory_id_here), break on auto_refcount_underflow_error to debug

调试控制台的示例转储是:

ScreenSaverEngine[1678:6807] client is <_NSCFURLProtocolBridge 0x20025ab00> {NSURLProtocol 0x200258ec0, CFURLProtocol 0x20029c400} ScreenSaverEngine(1678,0x102eda000) malloc: reference count underflow for 0x20025ab00, break on auto_refcount_underflow_error to debug.

您可以看到发生了下溢 <_NSCFURLProtocolBridge 0x20025ab00>

当我闯入 auto_refcount_underflow_error,它似乎堆栈追溯到 URLProtocolDidFinishLoading: 在:

id client = [self client];
...
[client URLProtocolDidFinishLoading:self];

这个问题似乎已经存在了一段时间,但在网上似乎没有任何答案:

http://lists.apple.com/archives/cocoa-dev/2008/May/msg01272.html http://www.cocoabuilder.com/archive/message/cocoa/2007/12/17/195056

该错误仅在垃圾收集环境中显示这些列出的错误。有关如何在不引起内存问题的情况下解决此问题的任何想法?我假设这可能与NSURLProtocol下面的CF类型不正确地发布有关?


6672
2017-07-11 03:30


起源

堆栈跟踪图片: img.skitch.com/20090711-qbt4s4jq87jk4g68iaawe7h1hg.png - Dave Martorana


答案:


上次WWDC我们用webkit工程师确认了这个错误,他可以在代码中看到错误,所以希望他们能解决它。解决方法是在initWithRequest方法中CFRetain客户端。

- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client
{
    // work around for NSURLProtocol bug
    // note that this leaks!
    CFRetain(client);

    if (self = [super initWithRequest:request cachedResponse:cachedResponse client:client])
    {
    }

    return self;
}

4
2018-01-12 18:21





这是_NSCFURLProtocolBridge实现中的一个错误。

请用 http://bugreport.apple.com/ 并提交一个错误。如果您包含此页面的URL,那将是值得赞赏的(如果您使用Radar#更新此页面,也会受到赞赏)。理想情况下,如果您可以附加屏幕保护程序的二进制文件,那将非常有用;无需任何来源。

幸运的是,它不应该导致崩溃。不幸的是,它可能会导致泄漏。


3
2017-08-05 03:44





此错误通常表示保留了对象 -retain,但随着发布 CFRelease()。如果你认为这不是你的目标(这不是一个可怕的信念),那么你应该打开另一个雷达。但是你应该首先环顾四周,看看是否有你正在使用的CF对象 -retain 什么时候你应该使用 CFRetain()

剩下的就是在黑暗中拍摄....

您可以通过升级堆栈并查看传递给这些C ++方法的参数(或者特别是 auto_zone_release)。在gdb中尝试这个,试着看看第一个参数是什么:

p *($esp)

看看你是否可以获得有关被传递对象的任何见解。如果你幸运的话,也许这会奏效:

po (id)(*($esp))

1
2017-07-28 00:17



Rob - 在GC环境中,不是 - 调用NOOPs吗?我认为这是一个错误,我将打开一个关于它的雷达漏洞。谢谢! - Dave Martorana
-retain是GC中的NOOP,但CFRetain()不是。因此,如果你调用-retain然后调用CFRelease(),你就会失去平衡。 - Rob Napier


我解决了这个问题 CFRetain - 客户,和 CFRelease - 在下一次电话会议上再次播出 startLoading

-(void)startLoading 
{
        if ( client ) CFRelease(client);
        client = [self client];
        CFRetain(client);

当然,最终确定

-(void)finalize
{
    if ( client ) CFRelease(client);
    [super finalize];
}

client 是一个实例变量 NSURLProtocol 子类。


1
2018-01-13 12:09





这是我提交过的错误报告:

http://openradar.appspot.com/8087384

可能也值得提交,它已经被复制了,但修复它会很好。

正如Alex所说,Apple开发人员在我面前查看了源代码,并通过我们的示例轻松找到了问题。


1
2018-01-17 05:35



这个bug被关闭为rdar:// 8070298,这似乎是在Lion中修复的。 - Quinn Taylor


有时在打开的对话框过滤器中使用NSURL会出现相同的错误。 对我来说,在我不再需要它之后,将它设置为nil就足够了。


0
2017-11-18 12:59