java - 为什么 Java native 缓冲区那么慢?

标签 java android performance algorithm image-processing

我试图优化我在 Android 设备上运行的简单区域增长算法。最初我使用 ArrayList 来保存属于一个区域的点。每个点都由一个 Point 实例描述,每个点都需要实例化。该算法大约 15 秒 找到了图像中大约 1 百万像素的所有区域。

Point 类非常简单:

class Point
{
    public int x, y;
}

我认为我可以通过减少 Point 实例化的数量来减少计算时间。因此,我将点列表替换为 Region 类,该类利用 native 缓冲区进行点征集:

private int capacity;
private int pointsCount = 0;

private ByteBuffer buffer;
private IntBuffer intBufferView;

根据点数计算所需的字节缓冲区大小:

private static int getByteBufferSize( int capacity )
{
    // 4 bytes per integer and 2 integers per point
    return capacity * 4 * 2;
}

初始容量我选的是100,不过我也试过设置成10,也就是ArrayList的初始容量,我在测试中试过设置成最大区域的大小图片:

public Region()
{
    this.capacity = 100;
    this.buffer = ByteBuffer.allocateDirect( getByteBufferSize( 100 ) );
    this.intBufferView = buffer.asIntBuffer();
}

为了向区域添加点,我使用了这种方法:

public void add( final Point point )
{
    if( pointsCount >= capacity )
    {
        grow();
    }

    final int offset = 2 * pointsCount;
    intBufferView.put( offset + 0, point.x );
    intBufferView.put( offset + 1, point.y );
    ++pointsCount;
}

对于读取某个点,通过索引标识,这个方法:

public void fetchPoint( Point p, int pointIndex )
{
    final int offset = 2 * pointIndex;
    p.x = intBufferView.get( offset + 0 );
    p.y = intBufferView.get( offset + 1 );
}

我实现了与 ArrayList 使用的策略相同的增长策略:

private void grow()
{
    capacity = ( capacity * 3 ) / 2 + 1;
    final int bufferSize = getByteBufferSize( capacity );
    final ByteBuffer newBuffer = ByteBuffer.allocateDirect( bufferSize );
    newBuffer.put( buffer );
    newBuffer.rewind();
    buffer = newBuffer;
    intBufferView = buffer.asIntBuffer();
}

但是,通过这种优化,区域增长算法需要大约 33 秒才能完成同一幅图像。这是我无法解释的性能下降。是我的实现,整个想法,还是这里有什么问题?

最佳答案

坦率地说,我认为整个想法都是错误的。 Buffer类针对与您不同的用户案例进行了优化;即在 I/O 设备之间传输数据(广义上。

如果您想要(比当前)更好的性能,请替换 Bufferint[] .我预测您会看到较小的性能下降(与 ArrayList<Point> 版本相比),但您仍然会看到下降。这是您为节省内存而付出的代价。

关于java - 为什么 Java native 缓冲区那么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24070327/

相关文章:

javascript - javascript 事件监听器用汇编语言编译成什么

c++ - STL 是否首先设置相等运算符检查大小?

java - 如何使用 Spark 的 Direct Stream for Kafka 设置消费者组提交的偏移量?

java - 通过他的属性获取一个元素

java - Spring 网络流 : how is a request handled?

java - 是否可以用 JSR-330 @Scope 变体替换 Spring @Scope ("request")?

java - 如何获取依赖包的版本号?

android - MvvmCross Android - 替代按钮命令的 RelativeSource 绑定(bind)

xml - 使用 XML 为 Android 显示自定义标题栏

java - 寻找递归解的迭代解