巨大的内存泄漏NSData

时间:2014-01-21 07:57:03

标签: objective-c memory-leaks automatic-ref-counting

我正致力于音乐流媒体应用。我目前收到巨大内存泄漏的迹象。仪器说它与下面的代码有关。在while循环期间分配了一些内存块。我打开了ARC。我已经用尽所有选项,需要更多的想法

NSData * ringBufferReadData = [NSData dataWithBytes:readPointer length:allBytesAvailable];
// NSLog(@"READER: THESE ARE THE BYTES WE ARE ABOUT TO READ FROM RING BUFFER %lu ",allBytesAvailable);

[ringBuffer didReadLength:allBytesAvailable];

UInt32 ringBufferReadDataOffset = 0;

while (ringBufferReadDataOffset < allBytesAvailable) {

    int packetBytesFilled = [[ringBufferReadData subdataWithRange:NSMakeRange(12 + ringBufferReadDataOffset, 4)] pm_int32AtOffset:0];

    int packetDescriptionsBytesFilled = [[ringBufferReadData subdataWithRange:NSMakeRange(16 + ringBufferReadDataOffset, 4)] pm_int32AtOffset:0];

    int offset = AUDIO_BUFFER_PACKET_HEADER_SIZE + ringBufferReadDataOffset;
    NSData* audioBufferData = [NSData dataWithBytes:(char *)([ringBufferReadData bytes] + offset) length:packetBytesFilled];

    offset += packetBytesFilled ;
    NSData *packetDescriptionsData = [NSData dataWithBytes:(char *)([ringBufferReadData bytes] + offset) length:packetDescriptionsBytesFilled];

    UInt32 inNumberPackets = packetDescriptionsBytesFilled/AUDIO_STREAM_PACK_DESC_SIZE;
    AudioStreamPacketDescription *inPacketDescriptions;

    inPacketDescriptions = [self populatePacketDescriptionArray:packetDescriptionsData
                                        packetDescriptionNumber:inNumberPackets];

    if (inPacketDescriptions[0].mDataByteSize > 65536)
    {
        NSLog(@"packet description size is abnormally large.. soething is wrong");
    }

    [self handleAudioPackets:[audioBufferData bytes]
                 numberBytes:packetBytesFilled
               numberPackets:inNumberPackets
          packetDescriptions:inPacketDescriptions];

    ringBufferReadDataOffset += AUDIO_BUFFER_PACKET_HEADER_SIZE + packetBytesFilled + packetDescriptionsBytesFilled;

    free(inPacketDescriptions);
}

1 个答案:

答案 0 :(得分:1)

你在那个循环中创建了大量的临时对象;如果其中一些最终出现在自动释放池中而不是明确地-release d,那么它们会累积,因为你的循环中没有@autoreleasepool。严格来说,这不是内存泄漏本身(因为它最终会被释放),但它可能看起来像是仪器中的一个。

尝试重写一下你的循环,删除一些不必要的NSData对象。 e.g:

[ringBuffer didReadLength:allBytesAvailable];

const uint8_t *ptr = readPointer;
const uint8_t *end = ptr + allBytesAvailable;

while (end - ptr >= AUDIO_BUFFER_PACKET_HEADER_SIZE) {
    // Might be better if you had a struct type; also, you may need to byte swap?
    uint32_t packetBytesFilled = *(uint32_t *)(ptr + 12);
    uint32_t packetDescriptionsBytesFilled = *(uint32_t *)(ptr + 16);

    ptr += AUDIO_BUFFER_PACKET_HEADER_SIZE;

    // Should check for buffer overrun here
    if (end - ptr < packetBytesFilled)
        break;

    const uint8_t *audioData = ptr;

    ptr += packetBytesFilled;

    // Check for overrun here too (combining the two checks is tricky for 32-bit pointers)
    if (end - ptr < packetDescriptionsBytesFilled)
        break;

    /* Could get rid of this one too if -populatePacketDescriptionArray took a byte pointer;
       at the very least, if you know that this NSData is never retained, you could change to
       using +dataWithBytesNoCopy:length:freeWhenDone: to avoid unnecessary data copying */
    NSData *packetDescriptionsData = [NSData dataWithBytes:ptr length:packetDescriptionsBytesFilled];

    UInt32 inNumberPackets = packetDescriptionsBytesFilled/AUDIO_STREAM_PACK_DESC_SIZE;
    AudioStreamPacketDescription *inPacketDescriptions;

    inPacketDescriptions = [self populatePacketDescriptionArray:packetDescriptionsData
                                        packetDescriptionNumber:inNumberPackets];

    if (inPacketDescriptions[0].mDataByteSize > 65536)
    {
        NSLog(@"packet description size is abnormally large.. soething is wrong");
    }

    // Assuming no exceptions here otherwise you need @try{}...@finally{} to call free()
    [self handleAudioPackets:audioData
                 numberBytes:packetBytesFilled
               numberPackets:inNumberPackets
          packetDescriptions:inPacketDescriptions];

    ptr += packetDescriptionsBytesFilled;

    free(inPacketDescriptions);
}

一旦你摆脱了额外的NSData个对象,你的循环中几乎没有可见的内存相关活动,所以你可以泄漏的唯一地方是-populatePacketDescriptionArray:packetDescriptionNumber:和{{1} }}。或者,正如我在评论中所说,如果-handleAudioPackets:numberBytes:numberPackets:packetDescriptions:]要抛出异常(在这种情况下,你会泄漏-handleAudioPackets:numberBytes:numberPackets:packetDescriptions:的内存,因为该部分周围没有inPacketDescriptions