2013-05-21 14 views
9

だから、私は概念的な疑問を持っています。私は低レベルのオーディオを作る目的でAndroid上のJNIと仕事をしてきました。私はC/C++でたくさんのオーディオコーディングを行ったので、これはあまり問題ではないと考えました。私は自分の「ネイティブ」コードでC++を使うことにしました(誰がOOPを愛していないのですか?)。私が遭遇した問題は、奇妙な一つであることが(私には)そうです:私はC++コードでオーディオを処理するためのオブジェクトを作成し、ときに私は、この上のメソッドを呼び出す、Javaへのこのオブジェクト(またその逆)を渡すことはありませんオブジェクトはガベージコレクションをかなり頻繁に呼び出すようです。これは、音声コールバックの内部に起こっているので、結果は吃音オーディオであり、そしてIは、線に沿って頻繁にメッセージ得る:私は静的関数を作成する(というよりも上のメンバメソッドを呼び出すことによって、同じ操作を実行すると、しかしAndroid JNIネイティブコードのC++オブジェクトはガベージコレクションを呼び出しますか?

WAIT_FOR_CONCURRENT_GC blocked 23ms 

をmemeberオブジェクト)は、アプリケーションのパフォーマンスは良いと思われ、私はもはや上記のログメッセージが表示されます。基本的には

、ネイティブコード内のメンバーオブジェクトのメンバメソッドを呼び出すよりも優れた性能を持っている必要があり、静的な関数を呼び出す何らかの理由があるのでしょうか?は具体的には、メンバーオブジェクト、またはガベージコレクションに関与JNIプロジェクトのネイティブコード内で完全に住んで限られた範囲変数ですか? C++コールスタックはGCに含まれていますか? JNIプログラミングに関して、C++メモリ管理がJavaメモリ管理とどのように合致するかについて、誰かが私に与える洞察はありますか?つまり、JavaとC++の間でデータを渡さない場合、C++コードを書く方法はJavaメモリ管理(GCなど)に影響しますか?

私は例を与えることを試みることを許可します。あなたが洞察力を持っていると思うなら、ここで読むのをやめるのは大歓迎です。

私は、オブジェクトのカップルを持っています。オーディオエンジンの作成、出力の初期化などを担当するもの。これはHelloAudioJNIと呼ばれています(コンパイル可能なサンプルを置いていないのは申し訳ありませんが、コードがたくさんあります)。

class CHelloAudioJNI { 

    ... omitted members ... 

    //member object pointers 
    COscillator *osc; 
    CWaveShaper *waveShaper; 

    ... etc ... 

public: 
    //some methods 
    void init(float fs, int bufferSize, int channels); 

    ... blah blah blah ... 

私にはさらに2つのクラスがあります。ウェーブシェイパークラスには、次のようになります。

class CWaveShaper : public CAudioFilter { 
protected: 
    double *coeffs; 
    unsigned int order;//order 
public: 
    CWaveShaper(const double sampleRate, const unsigned int numChannels, 
       double *coefficients, const unsigned int order); 

    double processSample(double input, unsigned int channel); 
    void reset(); 
}; 

は、この例では、すでにかなり長いためのが、今のところCAudioFilterクラス心配ないようにしましょう。 WaveShaperの.cppファイルは次のようになります。

CWaveShaper::CWaveShaper(const double sampleRate, 
         const unsigned int numChannels, 
         double *coefficients, 
         const unsigned int numCoeffs) : 
    CAudioFilter(sampleRate,numChannels), coeffs(coefficients), order(numCoeffs) 
{} 

double CWaveShaper::processSample(double input, unsigned int channel) 
{ 
    double output = 0; 
    double pow = input; 

    //zeroth order polynomial: 
    output = pow * coeffs[0]; 

    //each additional iteration 
    for(int iteration = 1; iteration < order; iteration++){ 
     pow *= input; 
     output += pow * coeffs[iteration]; 
    } 

    return output; 
} 

void CWaveShaper::reset() {} 

次にHelloAudioJNI.cppがあります。これが問題の肉体に入り込む場所です。

void CHelloAudioJNI::init(float samplerate, int bufferSize, int channels) 
{ 
    ... some omitted initialization code ... 

     //wave shaper numero uno 
    double coefficients[2] = {1.0/2.0, 3.0/2.0}; 
    waveShaper = new CWaveShaper(fs,outChannels,coefficients,2); 

    ... some more omitted code ... 
} 

[OK]を、すべてがこれまでの罰金だ:私はメンバーは以下のようなものを、init関数内で新しいを使用して、適切にオブジェクトを作成します。そして、オーディオコールバックの内側に、私たちはそうのようなメンバオブジェクトにいくつかのメンバー・メソッドを呼び出します。

void CHelloAudioJNI::processOutputBuffer() 
{ 
    //compute audio using COscillator object 
    for(int index = 0; index < outputBuffer.bufferLen; index++){ 
     for(int channel = 0; channel < outputBuffer.numChannels; channel++){ 
      double sample; 

      //synthesize 
      sample = osc->computeSample(channel); 
      //wave-shape 
      sample = waveShaper->processSample(sample,channel); 

      //convert to FXP and save to output buffer 
      short int outputSample = amplitude * sample * FLOAT_TO_SHORT; 
      outputBuffer.buffer[interleaveIndex(index,channel)] = outputSample; 
     } 
    } 
} 

これは頻繁に音声途切れやガベージコレクションに関するメッセージの多くを生成するものです。しかし、私はすぐにコールバックの上HelloAudioJNI.cppにCWaveShaper :: processSample()関数をコピーして代わりに、直接のメンバ関数を呼び出す場合:

sample = waveShape(sample, coeff, 2); 

は、その後、私は私のアンドロイドから出てくる美しい美しいオーディオを取得します私はガーベッジコレクションについてのこのような頻繁なメッセージを受け取っていません。もう一度質問があり、は、メンバーオブジェクト、またはガベージコレクションに関与JNIプロジェクトのネイティブコード内で完全に住んで限られた範囲変数ですか? C++コールスタックはGCに含まれていますか? JNIプログラミングに関して、C++メモリ管理がJavaメモリ管理とどのように合致するかについて、誰かが私に与える洞察はありますか?つまり、JavaとC++の間でデータを渡さない場合、C++コードを書く方法はJavaメモリ管理(GCなど)に影響しますか?

答えて

3

CHelloAudioJNI::init(...) 格納ウェーブシェイパーのスタック変数(double coefficients[2])へのポインタ。範囲が外れた後にwaveShaper->coeffsにアクセスすると、BadThings(tm)が発生します。

はあなたのCWaveShaperコンストラクタで配列のコピーを作成します(そして、あなたのデストラクタでそれを削除することを忘れないでください)。またはstd::arrayを使用してください。

+0

これは接線である可能性があります。係数は読み込まれるが書き込まれないもののように聞こえるからです。したがって、アクセスされたときの値は不確定な可能性がありますが、スタックの破損が発生することはすぐには分かりません。 –

+0

@ChrisStratton、あなたのコメントを説明できますか?私はあなたが意味することを理解していません。 – xaviersjs

+0

ここで提起問題はもはや割り当てられたメモリからアクセス係数の値が不正確である可能性が高いとあなたが解決しなければならないものです。しかし、あとで係数を変更しようとしない限り、これは不適切なプログラムフローを引き起こすことはありません。これは、この答えによって暗黙的に提供されるガベージコレクションの唯一の説明のようです。すべての入力に対して有効な計算に使用する係数のみを*読み込んだ場合、「BadThings(tm)」は「間違った計算結果」に限定されます。 –

5

C++オブジェクトとのDalvikのガベージコレクションの間に関係はありません。 Dalvikは、独自の内部ストレージ以外のネイティブヒープの内容には関心がありません。 Javaソースから作成されたすべてのオブジェクトは、ガベージコレクションが行われる「管理された」ヒープ上に存在します。

のDalvik GCは、ネイティブスタックを調べません。 VMに知られている各スレッドには、インタープリタが使用するための別個のスタックがあります。

C++コンストラクタから新しい管理対象オブジェクトを作成する、またはJavaファイナライザからネイティブオブジェクトを削除するなど、何らかの方法でオブジェクトをペアにしてリレーションシップを作成することを選択した場合のみ、C++オブジェクトとマネージオブジェクトが関連します。

あなたは、マネージヒープ上で最も最近作成されたオブジェクトを参照してくださいDDMS/ADTの「アロケーショントラッカー」機能を使用し、それらが割り当てられているところからすることができます。あなたがGCの暴走中にそれを実行する場合、それが何を引き起こしているのかを知ることができるはずです。

また、logcatメッセージにはプロセスとスレッドID(コマンドラインで使用する場合はadb logcat -v threadtime)が表示されます。これは、メッセージがアプリケーションから送信されていることを確認し、GCアクティビティ〜で起こっている。スレッド名は、DDMS/ADTの[スレッド]タブで確認できます。