ブロック分割した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