我的應用程序有一個由RemoteIO AudioUnit框架調用的音頻記錄回調。 AudioUnit在與主線程不同的線程中調用回調,因此它沒有自動釋放池。在此回調中,我執行以下操作:音頻回調線程(iOS)中的內存泄漏
- 分配記錄樣本的緩衝區。
- 請致電
AudioUnitRender
填寫此緩衝區。 - 使用
freopen
打開文件進行記錄。 - 調用音頻處理方法。
- 根據音頻,使用
performSelectorOnMainThread
(發送到視圖控制器)更新主線程上的UI。
另外,我有一個名爲testFilter()
功能,做一些基準測試,這是我在視圖控制器的viewDidLoad
調用,音頻會話初始化之前,因此之前的音頻調用回調函數的第一次。在這個函數中,我分配一個緩衝區(使用malloc/free)並調用上面提到的相同的音頻處理方法。現在
,問題是(設備,而不是模擬器上):
- 如果我註釋掉調用
testFilter()
,我沒有得到任何內存泄漏相關的消息。 - 如果我不叫
testFilter()
,我開始越來越一堆消息從音頻回調中(第5條消息是從testFilter()
方法我的日誌):
2011-01-20 23: 05:10.358 TimeKeeper的[389:307]初始化緩衝器...
2011-01-20 23:05:10.693 TimeKeeper的[389:307]進行...
2011-01-20 23:05 :10.696 TimeKeeper [389:307]處理緩衝區...
2011-01-20 23:05:15.772 TimeKeeper的[389:307]完成了...
2011-01-20 23:05:15.775 TimeKeeper的[389:307]經過時間5.073843
2011-01-20 23:05:16.319 TimeKeeper的[389:660F] * __NSAutoreleaseNoPool():有沒有到位池自動釋放類__NSCFData的對象0x137330 - 剛剛泄露
2011-01-20 23:05: 16.327 TimeKeeper [389:660f] * __NSAutoreleaseNoPool():類__NSCFData的對象0x1373a0自動釋放,不存在池 - 僅泄漏
等等。回調具有不同的線程,如日誌中所示。
爲什麼只有在音頻會話初始化之前調用並完成的函數纔會發生這些警告?我如何檢測泄漏?
附錄
相關的方法:
void testFilter() {
#if TARGET_IPHONE_SIMULATOR == 0
freopen([@"/tmp/console.log" cStringUsingEncoding:NSASCIIStringEncoding],"a",stderr);
#endif
int bufSize = 2048;
int numsec=100;
OnsetDetector * onsetDetector = [[OnsetDetector alloc] init];
AudioSampleDataType *buffer = (AudioSampleDataType*) malloc (44100*numsec * sizeof(AudioSampleDataType)); // numsec seconds of audio @44100
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mData = buffer;
bufferList.mBuffers[0].mDataByteSize = sizeof (AudioSampleDataType) * bufSize;
bufferList.mBuffers[0].mNumberChannels = 1;
//--- init buffer
NSLog(@"\n\n---***---***---");
NSLog(@"initializing buffer...");
for (int i = 0; i < 44100*numsec; ++i) {
*(buffer+i) = (AudioSampleDataType)rand();
}
NSLog(@"done...");
NSLog(@"processing buffer...");
CFAbsoluteTime t0 = CFAbsoluteTimeGetCurrent();
for (int i = 0; (i+1)*bufSize < 44100*numsec; ++i) {
bufferList.mBuffers[0].mData = buffer + i * bufSize;
[onsetDetector process:&bufferList];
}
CFAbsoluteTime t1 = CFAbsoluteTimeGetCurrent();
NSLog(@"done...");
NSLog(@"elapsed time %1.6f",(double)(t1-t0));
free(buffer);
[onsetDetector release];
}
和:
OSStatus recordingCallback (void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
AudioBufferList bufferList;
// redundant
SInt16 *buffer = (SInt16 *)malloc (sizeof (AudioSampleDataType) * inNumberFrames);
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mData = buffer;
bufferList.mBuffers[0].mDataByteSize = sizeof (AudioSampleDataType) * inNumberFrames;
bufferList.mBuffers[0].mNumberChannels = 1;
ioData = &bufferList;
// Obtain recorded samples
OSStatus status;
MainViewController *mainViewController = (MainViewController *)inRefCon;
AudioManager *audioManager = [mainViewController audioManager];
SampleManager *sampleManager = [audioManager sampleManager];
status = AudioUnitRender([audioManager audioUnit],
ioActionFlags,
inTimeStamp,
inBusNumber, //1
inNumberFrames,
ioData);
#if TARGET_IPHONE_SIMULATOR == 0
freopen([@"/tmp/console.log" cStringUsingEncoding:NSASCIIStringEncoding],"a",stdout);
#endif
// send to onset detector
SInt32 onset = [[audioManager onsetDetector] process:ioData];
if (onset > 0) {
NSLog(@"onset - %ld\n", sampleManager.recCnt + onset);
//--- updating the UI - must be done on main thread
[mainViewController performSelectorOnMainThread:@selector(tapButtonPressed) withObject:nil waitUntilDone:NO];
[mainViewController performSelectorOnMainThread:@selector(onsetLedOn) withObject:nil waitUntilDone:NO];
}
sampleManager.recCnt += inNumberFrames;
free(buffer);
return noErr;
}
謝謝。我知道autorelease池,我知道它會使錯誤消息消失,但我不明白兩件事:1.什麼對象正在嘗試autorelease,以及2.爲什麼這些消息只出現在我調用一個函數主線程,甚至在音頻線程創建之前。 – 2011-01-21 12:28:40
**更新**即使我將所有回調命令放入自動釋放池(並在末尾調用[池漏]),仍會出現錯誤消息。任何其他想法? – 2011-01-21 12:50:53