ページ更新: 2009-12-10 (木) (4100日前)
(新規作成: 2004-07-15) Java2 SE 1.4 で追加された nio についてのメモ。 なお、Java SE 7あたりで nio2 が追加されるようだ。nioでは不十分な機能があったらしい。 目次 [編集]情報源 #IBM developerWorks:
Java in the Box:
マイコミジャーナル:
DirectByteBuffer の領域の大きさを指定する (2004-10-14) #DirectByteBuffer の領域の大きさを指定するコマンドラインオプション。文書化されていないらしい。 java -XX:MaxDirectMemorySize=10m 実行するクラス名
メモ #[編集]MappedByteBufferを廃棄するには (2004-07-15, 2009-10-22) #
メモリマップ用の領域は有限なので、不要になったら廃棄したい。
以下、挙動を確認するためのコード: // -*-mode:java; coding:utf-8;-*- import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public final class MappedBufferLimit { public static void main(final String[] args) { System.out.println("java.runtime.version=" + System.getProperty("java.runtime.version")); try { final int loops = 20; final int fileSize = Integer.MAX_VALUE / loops; // メモリにマップするファイルを作成する。 final File file = createTestFile(fileSize); file.deleteOnExit(); // 同一のファイル(path)を指定した回数 (LOOPS) だけ、メモリに割り付ける。 // Mapしてエラーが出たらGCしてリトライする。 doMapAndGc(file, loops); // Mapして例外が出たら、あきらめる。 doMap(file, loops); } catch (final IOException e) { e.printStackTrace(); } } private static File createTestFile(final int fileSize) throws IOException { final File file = File.createTempFile("map-test", "dat"); System.out.println("testfile=" + file.getAbsolutePath()); final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); try { final int chunkSize = 8 * 1024; final int loops = fileSize / chunkSize; final byte[] buf = new byte[chunkSize]; for (int i = 0; i < loops; i++) { bos.write(buf); } bos.flush(); } finally { bos.close(); } return file; } /** * 同一のファイルを指定した回数だけ、メモリに割り付ける。 * 例外が発生したら、ガーベッジコレクションを行った後、再度メモリに割り付ける。 */ private static void doMapAndGc(final File file, final int loops) throws IOException { System.out.println("---------------------------------------- doMapAndGc"); final Runtime runtime = Runtime.getRuntime(); for (int i = 1, s = loops; i <= s; i++) { System.out.println("doMapAndGc: count=" + i); MappedByteBuffer b; try { b = createMappedFile(file); } catch (final IOException e) { System.out.println("retry"); runtime.gc(); b = createMappedFile(file); } System.out.println("doMapAndGc: buffer=" + b); } } /** * 同一のファイルを指定した回数だけ、メモリに割り付ける。 * 例外が発生したら中断する。 */ private static void doMap(final File file, final int loops) throws IOException { System.out.println("---------------------------------------- doMap"); long limitSum = 0; long capacitySum = 0; for (int i = 1, s = loops; i <= s; i++) { System.out.println("doMap: count=" + i); MappedByteBuffer b = createMappedFile(file); limitSum += b.limit(); capacitySum += b.capacity(); System.out.println( " doMap: limitSum=" + limitSum + " capacitySum=" + capacitySum + " buffer=" + b); } } /** ファイルをメモリに割り付ける */ private static MappedByteBuffer createMappedFile(final File file) throws IOException, FileNotFoundException { final FileInputStream fis = new FileInputStream(file); final FileChannel channel = fis.getChannel(); final long size = channel.size(); final MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size); return buffer; } }
いろいろなJDKでコンパイルして実行するためのバッチファイル (MappedBufferLimit.cmd): c:\java\j2sdk1.4.2_18\bin\javac MappedBufferLimit.java c:\java\j2sdk1.4.2_18\bin\java MappedBufferLimit c:\java\jdk1.5.0_18\bin\javac -encoding utf-8 MappedBufferLimit.java c:\java\jdk1.5.0_18\bin\java MappedBufferLimit c:\java\jdk1.6.0_16\bin\javac -encoding utf-8 MappedBufferLimit.java c:\java\jdk1.6.0_16\bin\java MappedBufferLimit 以下のようにしてバッチファイルを実行する: C:> (MappedBufferLimit.cmd 2>&1) > result.txt 結果 (result.txt)。一部を省略している。なお、この結果には現れていないが、手元では J2SDK 1.4.2_18 と JDK 1.5.0_16では実行する毎にretryの成功/失敗が変わる: C:> c:\java\j2sdk1.4.2_18\bin\javac MappedBufferLimit.java C:> c:\java\j2sdk1.4.2_18\bin\java MappedBufferLimit java.runtime.version=1.4.2_18-b06 testfile=C:\Temp\map-test44811dat ---------------------------------------- doMapAndGc doMapAndGc: count=1 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] : (略) doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMapAndGc: count=15 retry ★retry (gc実行) したが、 java.io.IOException: このコマンドを実行するのに十分な記憶域がありません。 ★回避できなかった。 at sun.nio.ch.FileChannelImpl.map0(Native Method) at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:705) at MappedBufferLimit.createMappedFile(MappedBufferLimit.java:112) at MappedBufferLimit.doMapAndGc(MappedBufferLimit.java:77) at MappedBufferLimit.main(MappedBufferLimit.java:27) C:> c:\java\jdk1.5.0_18\bin\javac -encoding utf-8 MappedBufferLimit.java C:> c:\java\jdk1.5.0_18\bin\java MappedBufferLimit java.runtime.version=1.5.0_18-b02 testfile=C:\Temp\map-test2712936866145569816dat ---------------------------------------- doMapAndGc doMapAndGc: count=1 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] : (略) doMapAndGc: count=12 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMapAndGc: count=13 retry ★retry (gc実行)して、 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] ★回避できた doMapAndGc: count=14 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] : (略) doMapAndGc: count=20 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] ---------------------------------------- doMap doMap: count=1 doMap: limitSum=107372544 capacitySum=107372544 buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMap: count=2 doMap: limitSum=214745088 capacitySum=214745088 buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMap: count=3 doMap: limitSum=322117632 capacitySum=322117632 buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMap: count=4 doMap: limitSum=429490176 capacitySum=429490176 buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMap: count=5 java.io.IOException: このコマンドを実行するのに十分な記憶域がありません。 at sun.nio.ch.FileChannelImpl.map0(Native Method) at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:742) at MappedBufferLimit.createMappedFile(MappedBufferLimit.java:112) at MappedBufferLimit.doMap(MappedBufferLimit.java:95) at MappedBufferLimit.main(MappedBufferLimit.java:30) C:> c:\java\jdk1.6.0_16\bin\javac -encoding utf-8 MappedBufferLimit.java C:> c:\java\jdk1.6.0_16\bin\java MappedBufferLimit java.runtime.version=1.6.0_16-b01 testfile=C:\Temp\map-test4799407424205691796dat ---------------------------------------- doMapAndGc doMapAndGc: count=1 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] : (略) ★IOExceptionが発生しない doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] doMapAndGc: count=20 doMapAndGc: buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] ---------------------------------------- doMap doMap: count=1 doMap: limitSum=107372544 capacitySum=107372544 buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] : (略) ★IOExceptionが発生しない doMap: count=20 doMap: limitSum=2147450880 capacitySum=2147450880 buffer=java.nio.DirectByteBufferR[pos=0 lim=107372544 cap=107372544] |