2011-01-20 12 views
0

My appには、RemoteIO AudioUnitフレームワークから呼び出される音声録音コールバックがあります。 AudioUnitはメインスレッドとは別のスレッドでコールバックを呼び出します。したがって、オートリリースプールはありません。このコールバックでは、私は以下を行います:音声コールバックスレッド(iOS)のメモリリーク

  • 記録されたサンプルのバッファを割り当てます。
  • AudioUnitRenderを呼び出してこのバッファをいっぱいにします。
  • freopenを使用してログファイルを開きます。
  • オーディオ処理メソッドを呼び出します。
  • オーディオに応じて、performSelectorOnMainThread(ビューコントローラに送信)を使用してメインスレッドのUIを更新します。

はまた、私はオーディオコールバックが初めて呼び出され、したがって前に、オーディオセッションが初期化される前に、私はビューコントローラのviewDidLoadに呼び出すいくつかのベンチマークを行いtestFilter()と呼ばれる機能を持っています。この関数では、バッファ(malloc/freeを使用して)を割り当て、前述の同じオーディオ処理メソッドを呼び出します。

さて、問題は(デバイスではなく、シミュレータ上で)です:

  • 私はtestFilter()への呼び出しをコメントアウトした場合、私は任意のメモリ・リーク関連のメッセージを得ることはありません。

2011-01-20 23:

  • 私はtestFilter()を呼ぶならば、私はオーディオコールバック内からのメッセージの束を取得を開始(最初の5つのメッセージはtestFilter()方法から私のログがあります): 05:10.358計時[389:307]バッファを初期化...

    2011-01-20 23:05:10.693計時[389:307] ...

    2011-01-20 23時05分に行わ:10.696 TimeKeeper [389:307]処理バッファー...

    2011-01-20 23:05:15.772計時[389:307]に行わ...

    2011-01-20 23:05:15.775計時[389:307]の経過時間5.073843

    2011-01-20 23:05:16.319計時[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; 
    } 
    

    答えて

    0

    freopenの後にfcloseが付いていない問題が原因と考えられます。私はstderrを第3引数としてfreopenに渡しているので、ログメッセージはファイルにリダイレクトされます。コールバックの最後にfcloseを呼び出すと、メモリリークエラーは表示されません。

    いくつかの質問にはまだかかわらず、答えを必要とする:

    • autoreleaseプールを使用しても問題が解決しなかったのはなぜ? freopenCの機能なので、とにかく自動解放メッセージは送信されないためです。
    • エラーメッセージがスローされている唯一の状況は次のとおりです。
      • freopenfclose
      • freopenせずに、メインスレッド上の機能に使用されているfcloseせずに、別のスレッド上のオーディオコールバックで使用されています。 freopenは(としないメインスレッド上の)音声のみのコールバックスレッドで使用される場合、ある

    、エラーが表示されません。

    編集

    もう一つの奇妙な振る舞いは、両方のスレッドでfcloseを使用しますが、私はオーディオコールバックスレッドでメインスレッドとstderrstdoutを通過しない場合でも、私はエラーメッセージを取得することです。私はそれがより多くの1つのスレッドがあるときNSLogが呼び出される方法と関係があると思います。これに関する洞察は歓迎されます。

    +0

    この頭痛の最終的な結論は、 'freopen'と' NSLog'をまったく使っていないのですが、ファイル出力(Cの 'fprintf'やいくつかのCocoaファイルIOクラス) –

    2

    "ただ漏れた" エラーメッセージは、あなたがどこの方法(またはいくつかの他の方法で得るものですメソッド呼び出し)は、自動解放プールがない場合にオブジェクトautoreleaseを試行します。プールがなければ、解放が必要なオブジェクトを追跡するものは何もないので、それらは単に漏れてしまいます。

    メインスレッドでは、このようなプールは自動的に作成され管理されますが、セカンダリスレッドでは自分で行う必要があります。あなたがする必要がどのような

    は、プールを割り当てるために、あなたの関数を変更します:

    void myFunction() { 
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    
        // do stuff here 
    
        [pool release]; 
    } 
    

    そして、これは、エラーメッセージが離れて行くよう、及びリークを修正します。

    +0

    ありがとうございます。自動解放プールについて知っていますが、エラーメッセージが消えることはわかりますが、私は2つのことを理解できません。1.自動解放しようとしているオブジェクトと、2.なぜこれらのメッセージが表示されるのは、オーディオスレッドが作成される前でも、メインスレッド –

    +0

    **更新**すべてのコールバックコマンドを自動解放プールに入れても(最後に[プールドレイン]を呼び出す)、エラーメッセージはまだ発生しています。他のアイデア? –