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

发布于 2024-07-26 11:41:18 字数 1512 浏览 7 评论 0原文

基础知识是我有一个自定义的 NSURLProtocol。 在 startLoading 中,[self client] 的类型为:

<_NSCFURLProtocolBridge> {NSURLProtocol, CFURLProtocol}

问题是在垃圾收集环境中运行它。 因为我正在编写一个屏幕保护程序,所以我被迫对其进行垃圾收集。 然而, _NSCFURLProtocolBridge 协议似乎总是抛出:

malloc:(memory_id_here) 的引用计数下溢,在 auto_refcount_underflow_error 上中断进行调试

转储到调试控制台的示例如下:

ScreenSaverEngine[1678:6807] 客户端是 <_NSCFURLProtocolBridge 0x20025ab00> {NSURLProtocol 0x200258ec0,CFURLProtocol 0x20029c400} ScreenSaverEngine(1678,0x102eda000) malloc:0x20025ab00 的引用计数下溢,在 auto_refcount_underflow_error 上中断进行调试。

您可以看到 <_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 类型发布不当有关?

The basics are I have a custom NSURLProtocol. In startLoading, [self client] is of type:

<_NSCFURLProtocolBridge> {NSURLProtocol, CFURLProtocol}

The problem is running this in a garbage-collected environment. Because I'm writing a screensaver, I'm forced to make it garbage-collected. However, the _NSCFURLProtocolBridge protocol seems to always throw:

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

An example dump to the debug console is:

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.

You can see that the underflow occurs for <_NSCFURLProtocolBridge 0x20025ab00>.

When I break on auto_refcount_underflow_error, it seems to stack-trace back up to URLProtocolDidFinishLoading: in:

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

This problem seems to have existed for a while, but there seems to be no answer at all online:

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

The bug only shows itself in garbage-collected environments for these listed bugs as well. Any thoughts on how I can work around this without causing memory issues? I'm assuming this probably has something to do with the CF type underneath NSURLProtocol being released improperly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

郁金香雨 2024-08-02 11:41:19

这是我不久前提交的错误报告:

http://openradar.appspot.com/8087384

也许也值得归档,它已经被复制了,但最好能修复它。

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

Here is the bug report I had filed a while back:

http://openradar.appspot.com/8087384

Probably worth filing as well, it's already been dup-ed, but it would be nice to get it fixed.

As Alex said, an Apple developer looked at the source code in front of me and located the issue easily with the example we had.

尽揽少女心 2024-08-02 11:41:19

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

the same error comes sometimes using NSURL in open dialog filter.
for me it was enough to set it to nil explicitly after I don't need it anymore.

糖粟与秋泊 2024-08-02 11:41:18

上次 WWDC 上我们向一位 webkit 工程师确认了这个 bug,他可以在代码中看到这个 bug,所以希望他们能够修复它。 解决方法是在 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;
}

Last WWDC we confirmed this bug with a webkit engineer, he could see the bug right there in the code so hopefully they'll fix it. The workaround is to CFRetain the client in the initWithRequest method.

- (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;
}
多孤肩上扛 2024-08-02 11:41:18

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

请使用 http://bugreport.apple.com/ 并提交错误。 如果您包含此页面的 URL,我们将不胜感激(如果您使用 Radar # 更新此页面,我们也将不胜感激)。 理想情况下,如果您可以附加屏幕保护程序的二进制文件,那将非常有帮助; 无需来源。

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

It is a bug in the implementation of _NSCFURLProtocolBridge.

Please use http://bugreport.apple.com/ and file a bug. If you include the URL to this page, that would be appreciated (and if you update this page with the Radar #, that would be appreciated, too). Ideally, if you can attach a binary of your screensaver, that would be very helpful; no source needed.

Fortunately, it should not cause a crash. Unfortunately, it probably causes a leak.

何必那么矫情 2024-08-02 11:41:18

此错误通常表明对象是用 -retain 保留的,但用 CFRelease() 释放的。 如果您认为这不可能是您的目标(这并不是一个可怕的信念),那么您应该打开另一个雷达。 但您应该首先环顾四周,看看是否有一个 CF 对象正在使用 -retain,而您也许应该使用 CFRetain()

其余的都是在黑暗中拍摄......

您可以通过逐步提高堆栈并查看传递给这些 C++ 方法(或特别是 auto_zone_release)的参数来获得一些见解。 在 gdb 中尝试查看第一个参数中的内容:

p *($esp)

并查看是否可以深入了解正在传递的对象。 如果你幸运的话,也许这会起作用:

po (id)(*($esp))

This error generally indicates that an object was retained with -retain, but released with CFRelease(). If you believe that this could not be your object (and that's not a terrible belief), then you should open another Radar. But you should first look around and see if there's a CF object you're using -retain on when perhaps you should use CFRetain().

The rest of this is shooting in the dark....

You may gain some insight by stepping up the stack and looking at the parameters that are being passed to these C++ methods (or particularly auto_zone_release). Try this in gdb to try to see what's in the first parameter:

p *($esp)

And see if you can get any insight about the object being passed. Perhaps this will work if you're lucky:

po (id)(*($esp))
无妨# 2024-08-02 11:41:18

我通过 CFRetain-ing 客户端,并在下次调用 startLoading 时再次 CFRelease-ing 解决了这个问题

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

,当然, Finalize中的

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

clientNSURLProtocol子类的实例变量。

I worked around this issue by CFRetain-ing the client, and CFRelease-ing it again on the next call to startLoading

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

and, of course, in finalize

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

client is an instance variable of the NSURLProtocol subclass.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文