ブロック分割したOSMバイナリレコードファイルを一定数(現在は32)メモリに読み込んでおく。 必要に応じて、LRU(Least Recently Used)方式で入れ替えを行う。
バイナリデータは何も変更は加えず int配列として保有する。
ブロックのサイズは異なるため、メモリ領域は動的に確保しているため、スワップによりメモリの解放が起き、 ガーベージコレクションの対象となる。
class Block {
static final int MaxBlocks = 32;
static final Block[] blocks = new Block[MaxBlocks+1];
final static String DIR = "/storage/5BF6-842C/Map/";
int ix;
String path;
int ref_count; // 参照スレッド数
long time; // 最終参照時間
int[] vals; // OSMバイナリレコード
private static Block get(String dir, int Zoom, int bx, int by) {
String path = (dir + Zoom + "/" + bx + "/" + by + ".dat");
return get(path);
}
private static Block get(String path) {
long start = System.currentTimeMillis();
for (Block blk : blocks) {
if (blk != null && blk.ix > 0 && blk.path.equals(path)) {
return blk; // キャッシュにあった
}
}
// キャッシュになかった
// 空きブロックまたは最も古いブロックをさがす
long time = System.currentTimeMillis();
int ixLRU = -1;
for (int ix = 1; ix < blocks.length; ix++) {
Block block = blocks[ix];
if (block == null) {
blocks[ix] = new Block(ix); // プログラム起動後最初の割り当て
ixLRU = ix;
break; // 空きブロックが見つかった
}
if (block.ref_count == 0 && block.time < time) {
ixLRU = ix;
time = block.time;
}
}
if (ixLRU < 0) {
Log.e("Block", "ブロックが確保できない");
return blocks[0];
}
try {
Block block = blocks[ixLRU];
block.path = path;
block.vals = readAllInts(path);
block.time = System.currentTimeMillis();
long elapsed = System.currentTimeMillis() - start;
System.out.printf("#%d %s %dms %dKB\n",
ixLRU, path, elapsed, block.vals.length/1024);
return block;
} catch (IOException e) {
e.printStackTrace();
return blocks[0]; //null;
}
}
}
int配列への読み込みはパフォーマンス上、少し凝ったプログラムとなっている。
8MB単位で読み込み、それを int配列に変換している。
static byte[] ba = new byte[8*1024*1024];
static int[] readAllInts(String file) throws IOException {
File f = new File(file);
if (!f.exists()) {
Log.d("get", "no file: " + file);
return new int[0]; // レコードなし
}
int file_length = (int)f.length();
int[] buffer = new int[file_length/4];
FileInputStream is = new FileInputStream(file);
for (int offset = 0; offset < file_length; ) {
int nbytes = is.read(ba);
IntBuffer intBuf = ByteBuffer.wrap(ba).order(ByteOrder.BIG_ENDIAN).asIntBuffer();
intBuf.get(buffer, offset/4, nbytes/4);
offset += nbytes;
}
is.close();
return buffer;
}
読み込み時間例を下に示す。
#1 /storage/5BF6-842C/Map/lands_split1/1/0.dat 38ms 9376KB #2 /storage/5BF6-842C/Map/lands_split5/28/12.dat 7ms 1604KB #3 /storage/5BF6-842C/Map/lands_low1/1/0.dat 3ms 327KB #4 /storage/5BF6-842C/Map/japanL3/7/2.dat 4ms 828KB #5 /storage/5BF6-842C/Map/japanL3/7/3.dat 14ms 3673KB #6 /storage/5BF6-842C/Map/japanM7/113/49.dat 7ms 1906KB #7 /storage/5BF6-842C/Map/japanM7/113/50.dat 13ms 3609KB #8 /storage/5BF6-842C/Map/japanM7/113/51.dat 2ms 14KB #9 /storage/5BF6-842C/Map/japanH7/113/50.dat 9ms 2461KB #10 /storage/5BF6-842C/Map/japanN7/113/50.dat 31ms 8566KB #11 /storage/5BF6-842C/Map/japanH13/7269/3228.dat 3ms 367KB #12 /storage/5BF6-842C/Map/japanH13/7269/3229.dat 3ms 636KB #13 /storage/5BF6-842C/Map/japanH13/7269/3230.dat 3ms 377KB #14 /storage/5BF6-842C/Map/japanH13/7269/3231.dat 3ms 451KB #15 /storage/5BF6-842C/Map/japanH13/7270/3228.dat 2ms 411KB #16 /storage/5BF6-842C/Map/japanH13/7270/3229.dat 3ms 484KB #17 /storage/5BF6-842C/Map/japanH13/7270/3230.dat 2ms 271KB #18 /storage/5BF6-842C/Map/japanH13/7270/3231.dat 2ms 265KB #19 /storage/5BF6-842C/Map/japanH13/7271/3228.dat 3ms 521KB #20 /storage/5BF6-842C/Map/japanH13/7271/3229.dat 2ms 444KB #21 /storage/5BF6-842C/Map/japanH13/7271/3230.dat 3ms 349KB #22 /storage/5BF6-842C/Map/japanH13/7271/3231.dat 3ms 371KB #23 /storage/5BF6-842C/Map/japanH13/7275/3224.dat 3ms 648KB #24 /storage/5BF6-842C/Map/japanH13/7275/3225.dat 3ms 590KB #25 /storage/5BF6-842C/Map/japanH13/7275/3226.dat 3ms 567KB #26 /storage/5BF6-842C/Map/japanH13/7275/3227.dat 4ms 654KB #27 /storage/5BF6-842C/Map/japanH13/7276/3224.dat 4ms 659KB #28 /storage/5BF6-842C/Map/japanH13/7276/3225.dat 3ms 647KB #29 /storage/5BF6-842C/Map/japanH13/7276/3226.dat 3ms 298KB #30 /storage/5BF6-842C/Map/japanH13/7276/3227.dat 1ms 70KB
DataInputStreamに、BufferedInputStreamを介在させてみる。
static int[] readAllInts(String file) throws IOException {
File f = new File(file);
if (!f.exists()) {
Log.d("get", "no file: " + file);
return new int[0]; // レコードなし
}
int file_length = (int)f.length();
int[] buffer = new int[file_length/4];
DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(file)));
for (int n = 0; n < buffer.length; n++) {
buffer[n] = dis.readInt();
}
dis.close();
return buffer;
}
結果は下に示すように1桁大きい読み込み時間となる。
#1 /storage/5BF6-842C/Map/lands_split1/1/0.dat 991ms 9376KB #2 /storage/5BF6-842C/Map/lands_split5/28/12.dat 137ms 1604KB #3 /storage/5BF6-842C/Map/lands_low1/1/0.dat 24ms 327KB #4 /storage/5BF6-842C/Map/japanL3/7/2.dat 60ms 828KB #5 /storage/5BF6-842C/Map/japanL3/7/3.dat 264ms 3673KB #6 /storage/5BF6-842C/Map/japanM7/113/49.dat 138ms 1906KB #7 /storage/5BF6-842C/Map/japanM7/113/50.dat 269ms 3609KB #8 /storage/5BF6-842C/Map/japanM7/113/51.dat 5ms 14KB #9 /storage/5BF6-842C/Map/japanH7/113/50.dat 176ms 2461KB #10 /storage/5BF6-842C/Map/japanN7/113/50.dat 614ms 8566KB #11 /storage/5BF6-842C/Map/japanH13/7269/3228.dat 28ms 367KB #12 /storage/5BF6-842C/Map/japanH13/7269/3229.dat 46ms 636KB #13 /storage/5BF6-842C/Map/japanH13/7269/3230.dat 29ms 377KB #14 /storage/5BF6-842C/Map/japanH13/7269/3231.dat 35ms 451KB #15 /storage/5BF6-842C/Map/japanH13/7270/3228.dat 31ms 411KB #16 /storage/5BF6-842C/Map/japanH13/7270/3229.dat 36ms 484KB #17 /storage/5BF6-842C/Map/japanH13/7270/3230.dat 23ms 271KB #18 /storage/5BF6-842C/Map/japanH13/7270/3231.dat 20ms 265KB #19 /storage/5BF6-842C/Map/japanH13/7271/3228.dat 38ms 521KB #20 /storage/5BF6-842C/Map/japanH13/7271/3229.dat 33ms 444KB #21 /storage/5BF6-842C/Map/japanH13/7271/3230.dat 28ms 349KB #22 /storage/5BF6-842C/Map/japanH13/7271/3231.dat 29ms 371KB #23 /storage/5BF6-842C/Map/japanH13/7275/3224.dat 48ms 648KB #24 /storage/5BF6-842C/Map/japanH13/7275/3225.dat 43ms 590KB #25 /storage/5BF6-842C/Map/japanH13/7275/3226.dat 43ms 567KB #26 /storage/5BF6-842C/Map/japanH13/7275/3227.dat 49ms 654KB #27 /storage/5BF6-842C/Map/japanH13/7276/3224.dat 49ms 659KB #28 /storage/5BF6-842C/Map/japanH13/7276/3225.dat 48ms 647KB #29 /storage/5BF6-842C/Map/japanH13/7276/3226.dat 23ms 298KB #30 /storage/5BF6-842C/Map/japanH13/7276/3227.dat 7ms 70KB