为啥 iOS AudioQueue 内存不断增加?

Posted

技术标签:

【中文标题】为啥 iOS AudioQueue 内存不断增加?【英文标题】:Why iOS AudioQueue memory constantly increasing?为什么 iOS AudioQueue 内存不断增加? 【发布时间】:2015-01-26 16:59:56 【问题描述】:

我有一个使用 AudioToolBox.framework ,AudioQueue 的 Play 音频类。

我遇到一个问题,每播放一段音频数据,内存都会增加,播放完成后内存不会减少。如果批量测试的话,会加到上百兆内存,想知道是什么原因导致内存变大了,每个对象每次pass的音频数据被释放了还是其他原因。

这是我的 playThread 类代码:

@interface PlayThread()

    BOOL transferDataComplete; // if thers is no data transfer to   playthread set transferDataComplete = yes;
    NSMutableArray *receiveDataArray;// audio data array
    BOOL isPlay;// if audioqueue start,isPlay = yes,

@end
#pragma mark class implementation
@implementation PlayThread
- (instancetype)init

    if (self = [super init]) 
        receiveDataArray = [[NSMutableArray alloc]init];
        isPlay = NO;
        transferDataComplete = false;
        bufferOverCount = QUEUE_BUFFER_SIZE;
        audioQueue = nil;
    
    return self;


// audio queue callback function
static void BufferCallback(void *inUserData,AudioQueueRef    inAQ,AudioQueueBufferRef buffer)

    USCPlayThread* player=(__bridge USCPlayThread*)inUserData;
    [player fillBuffer:inAQ queueBuffer:buffer];

// fill buffer
-(void)fillBuffer:(AudioQueueRef)queue queueBuffer:(AudioQueueBufferRef)buffer

    while (true)
        NSData *audioData = [self getAudioData];
        if( transferDataComplete && audioData == nil) 
           bufferOverCount --;
           break;
        
        else if(audioData != nil)
            memcpy(buffer->mAudioData, [audioData bytes] , audioData.length);
                buffer->mAudioDataByteSize = (UInt32)audioData.length;
                AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
                break;
            
            else
                break;
         // while
        if(bufferOverCount == 0)
            // stop audioqueue
            [self stopAudioQueue];
             dispatch_async(dispatch_get_main_queue(), ^
                if ([self.delegate respondsToSelector:@selector(playComplete)])     
                    [self.delegate playComplete];
                
            );
        
    

-(void)addPlayData:(NSData *)data

    NSUInteger count = 0;
     @synchronized(receiveDataArray)
        [receiveDataArray addObject:data];
    
 
 /**
 *  get data from receiveDataArray
 */
-(NSData*)getAudioData

    NSData *headData = nil;
    @synchronized(receiveDataArray)
        if(receiveDataArray.count > 0)
            headData = [receiveDataArray objectAtIndex:0];
            [receiveDataArray removeObjectAtIndex:0];
        
    
    return headData;


- (void)startPlay // start audioqueue to play audio data

    [self reset];
    [self open];
    for(int i=0; i<QUEUE_BUFFER_SIZE; i++)
    
        [self fillBuffer:audioQueue queueBuffer:audioQueueBuffers[i]];
    
    // audioqueuestart
    AudioQueueStart(audioQueue, NULL);

    @synchronized(self)
        isPlay = YES;
    
    if ([self.delegate respondsToSelector:@selector(playBegin)]) 
        [self.delegate playBegin];
    

-(void)createAudioQueue

    if (audioQueue) 
        return;
    
    AudioQueueNewOutput(&audioDescription, BufferCallback, (__bridge void *)(self), nil, nil, 0, &audioQueue);
    if(audioQueue)
        for(int i=0;i<QUEUE_BUFFER_SIZE;i++)
            AudioQueueAllocateBufferWithPacketDescriptions(audioQueue, EVERY_READ_LENGTH, 0, &audioQueueBuffers[i]);
        
    

-(void)stopAudioQueue

    if(audioQueue == nil)
        return;
    
    @synchronized(self)
        if(isPlay)
            isPlay = NO;
        
    
    AudioQueueStop(audioQueue, TRUE);

-(void)setAudioFormat

    audioDescription.mSampleRate = 16000;
    audioDescription.mFormatID = kAudioFormatLinearPCM;
    audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioDescription.mChannelsPerFrame = 1;
    audioDescription.mFramesPerPacket = 1;
    audioDescription.mBitsPerChannel = 16;
    audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/8) *      audioDescription.mChannelsPerFrame;
    audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ;
  

  -(void)close
    
       if (audioQueue) 
        AudioQueueStop(audioQueue, true);
        AudioQueueDispose(audioQueue, true);
        audioQueue = nil;
        isPlay = NO;
    


-(BOOL)open 
    if([self isOpen])
        return YES;
    
    [self close];
    [self setAudioFormat];
    [self createAudioQueue];
    return YES;


-(BOOL)isOpen

    return (audioQueue != nil);


- (void)reset

    bufferOverCount = QUEUE_BUFFER_SIZE;
    transferDataComplete = NO;


- (BOOL)isPlaying

    return isPlay;


- (void)disposeQueue

    if (audioQueue) 
        AudioQueueDispose(audioQueue, YES);
    
    audioQueue = nil;

 - (void)dealloc

    [self disposeQueue];

这里是 ViewContrller.m :

- (void)viewDidLoad 
[super viewDidLoad];

PlayThread *playThread = [[PlayThread alloc]init];
playThread.delegate = self;
self.playThread = playThread;

for (int  i = 0; i < 10; i++)
   // create empth audio data to simulate
    NSMutableData *data = [[NSMutableData alloc]initWithLength:10000];
    [self.playThread addPlayData:data];

    [self.playThread startPlay]; 

这是 PlayThread 的委托方法:

// When the play completely,then play once again,memory will continue to increase
- (void)playComplete

    dispatch_async(dispatch_get_main_queue(), ^
        for (int  i = 0; i < 10; i++)
        
            NSMutableData *data = [[NSMutableData alloc]initWithLength:10000];
            [self.playThread addPlayData:data];
        
        [self.playThread startPlay];
    );

Why memory has continued to increase, how can promptly release memory?

【问题讨论】:

最好的查看方法是在内存监视器上运行 Instruments。 几个问题,我会看看我是否不能稍后再看这个,但是 1) 这是使用 ARC 和 2) PlayThread 是不是 NSObject 的子类? 正在使用 ARC,PlayThread 是 NSObject 的子类。 遇到了同样的问题。我通过在 AudioQueueNewOutput 方法上将 CFRunLoopGetCurrent() 传递给 inCallbackRunLoop 解决了这个问题 【参考方案1】:

AudioQueueNewOutput(&audioDescription, BufferCallback, (__bridge void *)(self), nil, nil, 0, &audioQueue); 这里参数不能为nil

【讨论】:

以上是关于为啥 iOS AudioQueue 内存不断增加?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Unity ios 应用程序的文档和数据不断增加?

在 iOS 中通过 HTTP 获取图像时内存分配不断增加

AudioQueue 和 iOS4?

iOS - UILabel(CALayer) - VMalloc 内存不断增加

实际内存不断增加 - 从视图中删除子视图 - iOS (ARC)

适用于 iOS 的 Google Maps SDK 不断增加内存使用量