为啥 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 - UILabel(CALayer) - VMalloc 内存不断增加