iOS 實現音訊流播放器中踩的記憶體管理相關的坑

NO IMAGE

    App 作為工具應用,具備語音提醒的能力。語音是呼叫雲服務進行合成的,這樣做靈活些,新增提醒不用準備相應的語音檔案。雲服務合成音訊,以流的方式返回到端上,端上使用 Audio Queue 播放。流式播放,可以抽象為生產者-消費者問題。雲是我們的生產者,麥克風是我們的消費者。Audio Queue 已經把問題解決一半了,它建立了 Buffer,提供鉤子告訴我們Buffer可用,提供介面讓我們呼叫來告訴它“Buffer我們填滿了”。生產者-消費者問題需要協調生產者、消費者對快取的訪問。經典解決方案是利用訊號量。有了 GCD,我的用佇列來實現的。生產出音訊資料時,如果有 Buffer,填充 Buffer,Flush;否則將音訊檔案加入 producerBuffer,再次緩衝。麥克風消費了音訊檔案,空出了 Buffer,如果 producerBuffer 當中有資料,填充 Buffer,Flush;否則將 Buffer 放到可用 Buffer 列表(consumerBuffer)當中。這裡 producerBuffer,consumerBuffer 都可能在不同的執行緒被修改,需要保證執行緒安全,我的做法是對修改操作都加入佇列中進行序列,也可以用鎖,或者無鎖的機制類似 compareAndSwap。我遇到的記憶體問題是說我的 player 會被外部 retain,被內部 block retain,被 CoreFoundataion Audio Queue retain,在加上非同步的問題,偶現需要訪問時已經被回收的情況,SIGABRT、BAD_ACCESS 都出現了。主要原因是被 Audio Queue retain 的平衡操作不對,即呼叫 CFRelease 太早。在 BufferCallback 再次被呼叫的時候, player 已經 deallco。