我试图优化我在 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 设备之间传输数据(广义上。
如果您想要(比当前)更好的性能,请替换 Buffer
用int[]
.我预测您会看到较小的性能下降(与 ArrayList<Point>
版本相比),但您仍然会看到下降。这是您为节省内存而付出的代价。
关于java - 为什么 Java native 缓冲区那么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24070327/