2017-01-02 8 views
3

私のAndroidアプリでは、DoubleBufferオブジェクトに格納されたデータの処理を行うスレッドにループがあります。驚いたことに、put(DoubleBuffer)はメモリを割り当てているようです!DoubleBuffer.put()がメモリを割り当てているのはなぜですか?これを避けるにはどうすればよいですか?

これは私が期待していたはずのものですか?私には、NIOバッファについて理解していると思ったことすべてに反するようです。それを避けるために何かしなければならないことはありますか?

ループ内の2つのバッファ間を単純にコピーする最小限の例でこれを再現できます。私はこれが起こらない、put()への呼び出しをコメントアウトした場合

D/dalvikvm: GC_FOR_ALLOC freed 2032K, 55% free 6556K/14500K, paused 11ms, total 11ms 

:アンドロイド4.4.2を実行している物理的な電話でのAndroidメーカー経由で実行、ログは次のような行で満たされています。

ここで「空のアクティビティ」テンプレートの上に書かれた私は、この問題を再現コード、です:

public class MainActivity extends AppCompatActivity { 
    private Thread thread; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
    } 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     thread = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       DoubleBuffer buffer1 = DoubleBuffer.allocate(5000); 
       DoubleBuffer buffer2 = DoubleBuffer.allocate(buffer1.capacity()); 
       while (!Thread.interrupted()) { 
        // set remaining to capacity so that entire buffer is copied 
        buffer1.clear(); 
        buffer2.clear(); 
        buffer2.put(buffer1); 
        Thread.yield(); 
       } 
      } 
     }); 
     thread.setDaemon(true); 
     thread.start(); 
    } 

    @Override 
    protected void onStop() { 
     if (thread != null) { 
      thread.interrupt(); 
      thread = null; 
     } 
     super.onStop(); 
    } 
} 

そして、ここではapp/build.gradleの関連部分です:

AOSPのソースを閲覧
apply plugin: 'com.android.application' 

android { 
    compileSdkVersion 25 
    buildToolsVersion "25.0.2" 
    defaultConfig { 
     minSdkVersion 10 
     targetSdkVersion 25 
    } 
} 

dependencies { 
    compile 'com.android.support:appcompat-v7:25.1.0' 
} 
+0

コードは無意味です。空のバッファを別のバッファに置くと、データは転送されません。何かを試してみてください。 – EJP

+0

@EJP 'buffer.clear()。remaining()== buffer.capacity()'であるため、バッファ全体を転送する必要があります。テストはメモリ使用量のため、私は偽のテストデータを生成しませんでした。 –

答えて

1

は、これはまさに何が起こっているかのようです。 4.4.2DoubleBuffer.put(DoubleBuffer)に関連するコードは次のとおりです。彼らはSystem.arraycopy()のメリットを享受できるように

double[] doubles = new double[src.remaining()]; 
src.get(doubles); 
put(doubles); 

そこで彼らは、ヒープ割り当てのコストを払っています。この同じコードは、ByteBufferDoubleBufferビューで使用されているかどうかに関係なく使用されます。

私が知る限り、これは少なくとも少なくとも2.3までのコードです。 Androidの7.0のように、これは置き換えられました:

int n = src.remaining(); 
if (n > remaining()) 
    throw new BufferOverflowException(); 
for (int i = 0; i < n; i++) 
    put(src.get()); 

をですから、すべてのAndroidのバージョン間で、タイトなループでメモリを割り当てないようにしたい、とあなたが本当にしたい(または必要があります)バッファを使用している場合、あなたが必要あなた自身のput(DoubleBuffer)機能を実装してください。

while (fromBuffer.hasRemaining()) { 
    toBuffer.put(fromBuffer.get()); 
} 

それとも、あなたは配列担保バッファ(!fromBuffer.isDirect())からコピーしている場合:

toBuffer.put(fromBuffer.array(), fromBuffer.position(), fromBuffer.remaining()); 

状況は、すべての非バイトのバッファに同じである(たとえば、 IntBuffer,LongBuffer,ShortBuffer,FloatBuffer,CharBuffer)。

関連する問題