2017-01-02 60 views
3

在我的Android應用程序中,我有一個線程循環,用於處理存儲在DoubleBuffer對象中的數據。令我驚訝的是,put(DoubleBuffer)似乎在分配內存!爲什麼DoubleBuffer.put()分配內存,我應該如何避免這種情況發生?

這是我應該預料的事情嗎?對我而言,這似乎違背了我所理解的有關NIO緩衝區的一切。有什麼我應該做的,以避免它?

我可以用一個簡單的例子在一個循環中的兩個緩衝區之間進行復制來重現這一點。通過Android Studio中運行的是Android 4.4.2物理手機上運行,​​日誌充滿了類似下面的幾行:

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

如果我註釋掉調用put(),這不會發生。

這是我轉載這一問題,寫上「空活動」模板頂部的代碼:

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相關部分:

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

瀏覽AOSP源代碼,這看起來正是發生了什麼事情。對於DoubleBuffer.put(DoubleBuffer)4.4.2的相關代碼:

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

所以他們付出了堆分配的成本,使他們能夠獲得的System.arraycopy()好處。這個相同的代碼用於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()); 

的情況是所有的非字節的緩衝區相同( IntBufferLongBufferShortBuffer,FloatBuffer,CharBuffer)。

相關問題