java - 为什么 DoubleBuffer.put() 分配内存,我应该如何避免这种情况发生?

标签 java android memory nio

在我的 Android 应用程序中,我在线程中有一个循环,该循环对存储在 DoubleBuffer 对象中的数据进行一些处理。令我惊讶的是,put(DoubleBuffer)似乎在分配内存!

这是我应该预料到的吗?对我来说,这似乎违背了我对 NIO 缓冲区的所有理解。我应该做些什么来避免它?

我可以用一个简单的例子来重现这个,这个例子只是在一个循环中的两个缓冲区之间进行复制。在运行 Android 4.4.2 的物理手机上通过 Android Studio 运行,日志中充满了如下行:

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

如果我注释掉对 put() 的调用,则不会发生这种情况。

这是我重现此问题的代码,写在“空 Activity ”模板之上:

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'
}

最佳答案

浏览 AOSP 源代码,这似乎正是正在发生的事情。 4.4.2DoubleBuffer.put(DoubleBuffer)的相关代码是:

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

因此他们支付了堆分配的成本,以便他们可以获得 System.arraycopy() 的好处。同样的代码用于 ByteBufferDoubleBuffer View ,无论是否直接。

据我所知,这是至少可追溯到 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());

对于所有非字节缓冲区(IntBufferLongBufferShortBufferFloatBuffer,情况都是一样的>, CharBuffer).

关于java - 为什么 DoubleBuffer.put() 分配内存,我应该如何避免这种情况发生?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41420950/

相关文章:

java - 升级到 POI 4.0.0 后出现 java.lang.NoClassDefFoundError : Could not initialize class org. apache.poi.ooxml.util.DocumentHelper

java条件运算符,为什么下面的代码输出为真?

android - 使用 SQLiteDatabase.execSQL 执行多个语句

android - 如何在创建的 Activity 上再次重新启动线程

java - 获取位置并显示信息而不使用 if 语句?

java - 将 jetty 插件替换为 gretty 插件 gradle 时出错

Android mp3声音增加

memory - 有什么方法可以在不打开计算机的情况下检查我的计算机使用哪种内存?

java - java中内存使用量最小的Native Collection

ios - 如何在 iOS 应用程序中找到内存压力的来源