Помогите исправить выпуск утечки памяти - PullRequest
0 голосов
/ 06 февраля 2011
#import "VTM_AViPodReaderViewController.h"
#import <AudioToolbox/AudioToolbox.h> // for the core audio constants


#define EXPORT_NAME @"exported.caf"

@implementation VTM_AViPodReaderViewController

@synthesize songLabel;
@synthesize artistLabel;
@synthesize sizeLabel;
@synthesize coverArtView;
@synthesize conversionProgress;


#pragma mark init/dealloc
- (void)dealloc {
    [super dealloc];
}

#pragma mark vc lifecycle

-(void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
}

#pragma mark event handlers

-(IBAction) convertTapped: (id) sender {
    // set up an AVAssetReader to read from the iPod Library
    NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL];
    AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];

    NSError *assetError = nil;
    AVAssetReader *assetReader = [[AVAssetReader assetReaderWithAsset:songAsset
                                                               error:&assetError]
                                  retain];
    if (assetError) {
        NSLog (@"error: %@", assetError);
        return;
    }

    AVAssetReaderOutput *assetReaderOutput = [[AVAssetReaderAudioMixOutput 
                                              assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
                                                                        audioSettings: nil]
                                              retain];
    if (! [assetReader canAddOutput: assetReaderOutput]) {
        NSLog (@"can't add reader output... die!");
        return;
    }
    [assetReader addOutput: assetReaderOutput];

    NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [dirs objectAtIndex:0];
    NSString *exportPath = [[documentsDirectoryPath stringByAppendingPathComponent:EXPORT_NAME] retain];
    if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
        [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
    }
    NSURL *exportURL = [NSURL fileURLWithPath:exportPath];
    AVAssetWriter *assetWriter = [[AVAssetWriter assetWriterWithURL:exportURL
                                                          fileType:AVFileTypeCoreAudioFormat
                                                             error:&assetError]
                                  retain];
    if (assetError) {
        NSLog (@"error: %@", assetError);
        return;
    }
    AudioChannelLayout channelLayout;
    memset(&channelLayout, 0, sizeof(AudioChannelLayout));
    channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
    NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, 
                                    [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                    [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                    [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
                                    [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
                                    [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                    [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                    [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
                                    nil];
    AVAssetWriterInput *assetWriterInput = [[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
                                                                              outputSettings:outputSettings]
                                            retain];
    if ([assetWriter canAddInput:assetWriterInput]) {
        [assetWriter addInput:assetWriterInput];
    } else {
        NSLog (@"can't add asset writer input... die!");
        return;
    }

    assetWriterInput.expectsMediaDataInRealTime = NO;

    [assetWriter startWriting];
    [assetReader startReading];

    AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
    CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
    [assetWriter startSessionAtSourceTime: startTime];

    __block UInt64 convertedByteCount = 0;

    dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
    [assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue 
                                            usingBlock: ^ 
     {
         // NSLog (@"top of block");
         while (assetWriterInput.readyForMoreMediaData) {
            CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
            if (nextBuffer) {
                // append buffer
                [assetWriterInput appendSampleBuffer: nextBuffer];
                //              NSLog (@"appended a buffer (%d bytes)", 
                //                     CMSampleBufferGetTotalSampleSize (nextBuffer));
                convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
                // oops, no
                // sizeLabel.text = [NSString stringWithFormat: @"%ld bytes converted", convertedByteCount];

                NSNumber *convertedByteCountNumber = [NSNumber numberWithLong:convertedByteCount];
                [self performSelectorOnMainThread:@selector(updateSizeLabel:)
                                       withObject:convertedByteCountNumber
                                    waitUntilDone:NO];
            } else {
                // done!
                [assetWriterInput markAsFinished];
                [assetWriter finishWriting];
                [assetReader cancelReading];
                NSDictionary *outputFileAttributes = [[NSFileManager defaultManager]
                                                      attributesOfItemAtPath:exportPath
                                                      error:nil];
                NSLog (@"done. file size is %ld",
                        [outputFileAttributes fileSize]);
                NSNumber *doneFileSize = [NSNumber numberWithLong:[outputFileAttributes fileSize]];
                [self performSelectorOnMainThread:@selector(updateCompletedSizeLabel:)
                                       withObject:doneFileSize
                                    waitUntilDone:NO];
                // release a lot of stuff
                [assetReader release];
                [assetReaderOutput release];
                [assetWriter release];
                [assetWriterInput release];
                [exportPath release];
                break;
            }
        }

     }];
    NSLog (@"bottom of convertTapped:");
}

-(void) updateSizeLabel: (NSNumber*) convertedByteCountNumber {
    UInt64 convertedByteCount = [convertedByteCountNumber longValue];
    sizeLabel.text = [NSString stringWithFormat: @"%ld bytes converted", convertedByteCount];
}

-(void) updateCompletedSizeLabel: (NSNumber*) convertedByteCountNumber {
    UInt64 convertedByteCount = [convertedByteCountNumber longValue];
    sizeLabel.text = [NSString stringWithFormat: @"done. file size is %ld", convertedByteCount];
}


@end

У меня серьезные проблемы с утечкой памяти при конвертации. Из моего отладки и анализа, он показывает:

[assetReader release];
[assetReaderOutput release];
[assetWriter release];
[assetWriterInput release];
[exportPath release];

с сохранением 1 не освобождает. Может кто-нибудь помочь решить эту проблему? Мое приложение продолжает зависать после попытки конвертировать вторую песню.

Журнал отчетов

/Users/cocellmac08/Documents/iphonedev/trying/Classes/SecondViewController.m:835:3 Potential leak of an object allocated on line 827 and stored into 'assetReader'

/Users/cocellmac08/Documents/iphonedev/trying/Classes/SecondViewController.m:849:3 Potential leak of an object allocated on line 841 and stored into 'assetReaderOutput'

/Users/cocellmac08/Documents/iphonedev/trying/Classes/SecondViewController.m:877:3 Potential leak of an object allocated on line 861 and stored into 'exportPath'

/Users/cocellmac08/Documents/iphonedev/trying/Classes/SecondViewController.m:877:3 Potential leak of an object allocated on line 870 and stored into 'assetWriter'

/Users/cocellmac08/Documents/iphonedev/trying/Classes/SecondViewController.m:903:3 Potential leak of an object allocated on line 895 and stored into 'assetWriterInput'

Ответы [ 3 ]

5 голосов
/ 26 апреля 2011

Я исправил утечку памяти следующими строками в цикле while после оператора if / else, чтобы гарантировать, что nextBuffer действительно освобожден.

         CMSampleBufferInvalidate(nextBuffer);
         CFRelease(nextBuffer);
         nextBuffer = nil; // NULL?

Я не вижу каких-либо подробностей в документации по CMSampleBufferInvalidate, но я обнаружил, что на нее есть ссылки в другом месте, и, похоже, она помогает Я также называю CFRelease и, наконец, установить его на ноль. Установка его в NULL может быть более правильным способом, так как может быть предпочтительным рассматривать это как структуру уровня C, а NULL - это путь C, а nil - это Objective-C. Я запустил этот код, хотя утечки, и я не вижу основных утечек, которые я видел раньше. Я все еще вижу утечку 128 байтов. Я не могу проследить его до какой-либо строки кода, хотя. Это огромное улучшение по сравнению с ранее утечкой версии.

enter image description here

0 голосов
/ 12 мая 2012

Ты сделал мой день !!! TNX, я добавил, однако, это: CMSampleBufferInvalidate (nextBuffer); CFRelease (nextBuffer); nextBuffer = ноль; // НОЛЬ? сразу после этого: перерыв; }

вместо того, что указано в предыдущем комментарии, и похоже, что оно работает! снова.

0 голосов
/ 06 февраля 2011

Звучит, возможно, как две отдельные проблемы (если я понимаю вопрос);строить и анализировать выявление утечки.Авария это другая проблема.Опубликовать обратную трассировку.

Некоторые проблемы;никогда не проверяйте ошибку напрямую, чтобы увидеть, произошла ли ошибка.Вы должны быть:

if (!assetReader) {
    ... report assetError and return ...
}

Похоже, что есть несколько путей кода, в которых вы потеряете память;например, если canAddOutput: завершается неудачно, вы не отпускаете assetReader до возврата.

exportPath не требуется сохранять;если блоку это нужно, он сохранит его.

...