【发布时间】:2014-07-27 01:04:36
【问题描述】:
我正在尝试优化我在 Android 设备上运行的简单区域增长算法。最初我使用ArrayList 来保存属于一个区域的点。每个点都由Point 实例描述,需要为每个点实例化。算法用了大约 15 秒在大约 1 兆像素的图像中找到所有区域。
Point 类很简单:
class Point
{
public int x, y;
}
我认为我可以通过减少 Point 实例化的数量来减少计算时间。所以我用Region 类替换了点列表,该类利用本机缓冲区进行点登记:
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 秒才能在同一张图像上完成。这是我无法解释的性能下降。是我的实现,整个想法,还是这里有什么问题?
【问题讨论】:
-
我之前使用过 ByteBuffer,它不需要接近毫秒(甚至可能像你的情况一样接近几秒)来操作。检查您自己的算法 - 99.99% 的时间问题会出现在某个地方,而在 99.99% 的时间问题会出现在您在此处未发布的某些代码中。
-
我敢打赌,> 90% 的时间消耗(在显示的代码中)都花在了 grow() 中。分配和复制数据是昂贵的部分。
-
@theV0ID 也许是因为这个问题的决定性的,变相咆哮的语气? ;-)
标签: java android performance algorithm image-processing