【问题标题】:Memory from AVAudioPlayer in ivar not reusedivar 中来自 AVAudioPlayer 的内存未重用
【发布时间】:2012-12-13 08:03:20
【问题描述】:

我已经设置了一个实例变量来引用我用来在不同时间播放不同音频数据的 AVAudioPlayer。我的头文件包含:

AVAudioPlayer *player;

@property (nonatomic, retain) AVAudioPlayer *player;

我的实现文件包含:

- (void)playAudioData:(NSData *)data {
    NSMutableData *trimmedData = [NSMutableData dataWithData:data];
    int duration = 2; // seconds
    int dataLength = duration * 2 * 44100; // assumes 16-bit mono data
    [trimmedData setLength:dataLength];

    NSError *playerError;
    self.player = [[AVAudioPlayer alloc] initWithData:trimmedData error:&playerError];
    [self.player autorelease]; // ADDED
    if (playerError) {
        NSLog(@"player error: %@", playerError);
    }
    [self.player play];
    if (([[[UIDevice currentDevice] systemVersion] compare:@"6.0"] != NSOrderedAscending)&&([[[UIDevice currentDevice] systemVersion] compare:@"6.1"] == NSOrderedAscending)) {
        [trimmedData autorelease]; // ADDED
    }
}

- (void)dealloc {
    [self.player release];
}

在分析我的应用程序的内存使用情况时,我注意到调用此方法会将实时字节数增加 500k,这大约是我正在播放的音频数据的大小。但是,如果我再次调用该方法,则每次调用该方法时,活动字节会再增加 500k,并且还会增加一个。

根据this SO answer,我不应该在这里做任何不同的事情,因为设置 self.player 变量会减少现有值的保留计数。但我也尝试过释放 self.player 并将其设置为 nil,然后再给它一个新值,如this answer 所示,并在设置后自动释放 self.player,如this answer 所示。 (我没有收到初始化播放器的错误,就像最后一个答案中的问题一样。)在所有这些情况下,我的内存使用量一直在上升,并且再也不会下降。

我还需要做些什么来重用每次初始化音频播放器时分配的内存吗?

【问题讨论】:

  • 由于您明确调用 release,我假设您没有使用 ARC。在这种情况下,您发布的代码确实会泄漏音频播放器。您应该在分配播放器时自动释放播放器。如果这真的不能解决问题,那么还有其他问题。仪器是否显示泄漏,或者只是内存占用增加?
  • 另外,NSData 是从哪里来的?该代码也是可疑的......
  • 您对 NSData 的预感很好。事实上,我正在通过从中创建一个新的 NSMutableData 来修剪该数据......我只是编辑了我的答案以表明我的意思。我认为这无关紧要,因为我认为 dataWithData 方法会创建一个自动释放的对象。但是,如果我在此方法结束时手动释放 trimmedData 对象,则内存使用情况如预期:初始化播放器时它会上升,而当播放器停止时它会下降。那么现在,我真的需要自动释放播放器吗?仪器未显示泄漏。
  • 嗯,这还是很奇怪。 dataWithData 确实返回一个自动释放的对象。您不需要释放它。只有当您第二次致电playAudioData 时,您才会正式泄露您的播放器。如果您的播放器从未被解除分配,并且它是该 trimmedData 的唯一所有者,那么您向其发送额外的 release 将导致数据被回收,尽管该播放器仍然存在。最后一个挑剔,在您的dealloc 中,您应该将self.player 设置为nil,而不是显式释放它。
  • 这很奇怪。我发现使用 [trimmedData autorelease] 得到的结果与使用 [trimmedData release] 的结果相同。因此,除非我告诉它,否则显然数据不会自动发布。此外,我尝试在每次创建新播放器时手动释放播放器,而不是将其留给自动释放,但手动释放不会回收内存。所以我更新了我的问题以显示唯一对我有用的组合:自动释放播放器而不是手动释放它,并显式自动释放数据而不是依赖正常的自动释放行为。

标签: ios memory-management avaudioplayer


【解决方案1】:

在切换到Automatic Reference Counting [ARC] 之前,我的应用程序遇到了同样的问题,内存使用量会增加,直到应用程序崩溃,对吧?解决此问题的最快方法是在您的应用程序/项目中也使用 ARC,实际上它会完成管理内存的所有工作,并在需要时释放 AVAudioPlayer [你不需要任何 -void(dealloc) 在你的如果你使用 ARC] 的代码,所以没有更多的泄漏:-)。如果您不知道 ARC 是什么,您也可以查看此链接:

http://www.raywenderlich.com/5677/beginning-arc-in-ios-5-part-1

标题:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>

@interface YourViewController : UIViewController <AVAudioPlayerDelegate>
{
    AVAudioPlayer           *player;

    /* Your other code here */
}

/* Your other code here */

@end

主要:

#import "YourViewController.h"

@implementation YourViewController

/* Your other code here */

- (void)playAudioData:(NSData *)data
{
    NSError *playerError;
    self.player = [[AVAudioPlayer alloc] initWithData:data error:&playerError]; error:NULL];

    if (playerError)
    {
        NSLog(@"player error: %@", playerError);
    }

    [self.player play];

    /* No more need to release AVAudioPlayer, ARC will do the job */

}

/* Your other code here */

@end

【讨论】:

  • 呃...这不会需要对我已经庞大而复杂的应用程序进行一些重大改造吗?
  • @arlomedia 您可以尝试使用 XCode 的自动转换,只需单击几下它就会将您的代码转换为支持 ARC 并且完全自动 [它还会删除不必要的代码,例如“发布”],在链接之前有一段关于“自动转换”的段落检查它:-)。 XCode 也会对您的项目进行快照,因此如果您对 ARC 不满意,您可以立即恢复所有更改
  • 自动转换工具也很好用,也很简单!
猜你喜欢
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多