Как избежать потери подсчета ссылок в _NSCFURLProtocolBridge в пользовательском NSURLProtocol в среде GC - PullRequest
11 голосов
/ 11 июля 2009

Основы у меня есть на заказ 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

Эта ошибка проявляется только в средах со сборщиком мусора и для перечисленных ошибок. Любые мысли о том, как я могу обойти это без проблем с памятью? Я предполагаю, что это, вероятно, связано с тем, что тип CF под NSURLProtocol был выпущен неправильно?

Ответы [ 6 ]

4 голосов
/ 12 января 2011

На прошлой WWDC мы подтвердили эту ошибку с помощью инженера-вебкита, он мог видеть эту ошибку прямо в коде, так что, надеюсь, они исправят ее. Обходной путь должен CFRetain клиент в методе initWithRequest.

- (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;
}
3 голосов
/ 05 августа 2009

Это ошибка в реализации _NSCFURLProtocolBridge.

Пожалуйста, используйте http://bugreport.apple.com/ и сообщите об ошибке. Если вы включите URL этой страницы, это будет оценено (и если вы обновите эту страницу с помощью Radar #, это также будет оценено) В идеале, если вы можете прикрепить двоичный файл вашей заставки, это было бы очень полезно; источник не нужен.

К счастью, это не должно вызывать сбой. К сожалению, это, вероятно, вызывает утечку.

1 голос
/ 17 января 2011

Вот отчет об ошибке, который я недавно отправил:

http://openradar.appspot.com/8087384

Вероятно, также стоит подать, это уже дублировано, но было бы неплохо исправить это.

Как сказал Алекс, разработчик Apple посмотрел на исходный код передо мной и легко обнаружил проблему с примером, который у нас был.

1 голос
/ 13 января 2011

Я обошел эту проблему, CFRetain -ing клиент и CFRelease -ing снова при следующем вызове startLoading

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

и, конечно же, в доработке

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

client является переменной экземпляра подкласса NSURLProtocol.

1 голос
/ 28 июля 2009

Эта ошибка обычно означает, что объект был сохранен с -retain, но освобожден с CFRelease(). Если вы считаете, что это не может быть вашим объектом (и это не страшное убеждение), то вам следует открыть еще один радар. Но вы должны сначала осмотреться и посмотреть, есть ли объект CF, на котором вы используете -retain, когда, возможно, вам следует использовать CFRetain().

Остальное - стрельба в темноте ....

Вы можете получить некоторое представление, увеличивая стек и просматривая параметры, передаваемые этим методам C ++ (или, в частности, auto_zone_release). Попробуйте это в gdb, чтобы увидеть, что находится в первом параметре:

p *($esp)

И посмотрите, сможете ли вы получить какое-либо представление о передаваемом объекте. Возможно, это сработает, если вам повезет:

po (id)(*($esp))
0 голосов
/ 18 ноября 2011

такая же ошибка иногда возникает при использовании NSURL в фильтре открытого диалога. для меня этого было достаточно, чтобы установить его равным нулю после того, как он мне больше не нужен.

...