0

我有一个小项目,它从远程服务器读取 HTTP 流,对其进行解复用,提取音频流,将其解码为 16 位 PCM,然后输入相应的 AudioQueue。解码器/解复用器/提取器在单独的线程中运行,它使用我自己开发的阻塞队列(参见下面的代码)将解码的帧传递给 AudioQueue 回调。队列使用 NSMutableArray 来存储对象。

一旦这个东西在运行中,它就会泄漏插入到队列中的对象。内存分析器说 RefCt 在我期望它为 0 并由 ARC 释放时为 2。

以下是队列/出队方法:

- (id) dequeue {
    dispatch_semaphore_wait(objectsReady, DISPATCH_TIME_FOREVER);
    [lock lock];
    id anObject = [queue objectAtIndex:0];
    [queue removeObjectAtIndex:0];
    [lock unlock];
    dispatch_semaphore_signal(freeSlots);

    return anObject;
}

- (void) enqueue:(id)element {
    dispatch_semaphore_wait(freeSlots, DISPATCH_TIME_FOREVER);
    [lock lock];
    [queue addObject:element];
    [lock unlock];
    dispatch_semaphore_signal(objectsReady);
}

生产者线程这样做:

[pAudioFrameQueue enqueue:[self convertAVFrameAudioToPcm:audioFrame]];

“convertAVFrameAudioToPcm”方法如下所示:

- (NSData*) convertAVFrameAudioToPcm:(AVFrame*)frame {
    NSData* ret = nil;
    int16_t* outputBuffer = malloc(outputByteLen);
    // decode into outputBuffer and other stuff
    ret = [NSData dataWithBytes:outputBuffer length:outputByteLen];
    free(outputBuffer);

    return ret;
}

消费者这样做:

- (void) fillAvailableAppleAudioBuffer:(AudioQueueBufferRef)bufferToFill {
    @autoreleasepool {
        NSData* nextAudioBuffer = [pAudioFrameQueue dequeue];
        if (nextAudioBuffer != nil) {
            [nextAudioBuffer getBytes:bufferToFill->mAudioData]; // I know this is not safe
            bufferToFill->mAudioDataByteSize = nextAudioBuffer.length;
        } else {
            NSLog(@"ERR: End of stream...");
        }
    }
}

在我看来,当 fillAvailableAppleAudioBuffer 退出时,RefCt 应该变为 0,但显然 ARC 不同意并且不释放该对象。

我的简单队列代码中有错误吗?

还是我以错误的方式实例化 NSData?

还是我错过了一些关于 ARC 如何在线程之间工作的特殊规则?顺便说一句,生产者线程是这样开始的:

- (BOOL) startFrameFetcher {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                             (unsigned long)NULL),
                   ^(void) {
                       [self frameFetcherThread];
                    });
    return YES;
}

任何提示将不胜感激!

PS:最后但并非最不重要的一点是,我确实有另一个相同阻塞队列的实例,它存储我通过 NSTimer 出列和显示的视频帧。视频帧不泄漏!我猜这可能与线程有关。否则,我会期望在两个队列中都看到泄漏。

4

0 回答 0