[objective-c]帮助修复内存泄漏发布

发布时间: 2017/3/27 3:35:47
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.
#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'

解决方法 1:

我有固定内存泄漏与以下行在 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

赞助商