LoginSignup
7
8

More than 5 years have passed since last update.

java でファイルマップを行ったときの動きについて

Last updated at Posted at 2017-04-22

java でファイルマップを行ったときの動きについて

Javaでファイルマップを行ったときの動きについて調査したのでまとめる。

環境 CentOS7.3.1611、openjdk-1.8.0.131

C言語でopen+mmapシステムコールを利用し、ファイルをメモリ上にマップすることが出来るが、Javaでの利用が以前から気になっていたが
実際に試してみる。

以下のソースで評価する。

mmap01.java
import java.lang.Thread;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class mmap01
{
  public static void main(String[] args) throws Exception
  {
    for (int argc = 0; argc < args.length; argc++ ) {
      File file = new File(args[argc]);
      long length = file.length();

      System.out.println("file:" + args[0] + "  size:" + length);
      MappedByteBuffer in = new RandomAccessFile(file, "r")
                                .getChannel().map(FileChannel.MapMode.READ_ONLY, 0, length);
      for (long i = 0; i < length; i++) {
        in.get();
      }
      System.out.println("Finished reading");
    }
    System.out.println("wait");
    Thread.sleep(1000000);
  }
}

実際にマップしてみる。

ちなみに、Integer.MAX_VALUE を越える(2^31)ファイルの場合は、mapのタイミングで以下のようなエラーになる。
2^31-1のサイズではマップできた。

$ dd if=/dev/zero of=2gb bs=1 seek=2147483647 count=1
$ dd if=/dev/zero of=2gb-1 bs=1 seek=2147483646 count=1
$ dd if=/dev/zero of=2gb-2 bs=1 seek=2147483645 count=1
$ java mmap01 2gb
file:2gb  size:2147483648
Exception in thread "main" java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
    at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:869)
    at mmap01.main(mmap01.java:17)
$ java mmap01 2gb-1
file:2gb-1  size:2147483647
Finished reading
wait

この時の、javaプロセスのメモリマップ状態とJavaの状態を確認すると以下のようになっている。mmapでマップされているようだ。
jstatの結果からいくと、マップした領域はヒープの対象外のようだ。

$ cat /proc/$(pidof java)/maps
(略)
7f97c8000000-7f9848000000 r--s 00000000 00:26 5                          /mnt/hgfs/COMMON/Java_Mmap/2gb-1
(略)
$ jstat -gc $(pidof java)
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
1024.0 1024.0  0.0    0.0    8192.0   671.9    20480.0      0.0     4480.0 866.3  384.0   73.9       0    0.000   0      0.000    0.000

複数ファイルマップしたときはどうなるか。

$ java mmap01 2gb-1 2gb-2
file:2gb-1  size:2147483647
Finished reading
file:2gb-1  size:2147483646
Finished reading
wait

きちんと2ファイルともマップされている。ヒープも追加で読み込んだ領域(2^31-2)ほど増えていない。

$ cat /proc/$(pidof java)/maps
(略)
7fd08c000000-7fd10c000000 r--s 00000000 00:26 6                          /mnt/hgfs/COMMON/Java_Mmap/2gb-2
7fd10c000000-7fd18c000000 r--s 00000000 00:26 5                          /mnt/hgfs/COMMON/Java_Mmap/2gb-1
(略)
$ jstat -gc $(pidof java)
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
1024.0 1024.0  0.0    0.0    8192.0   835.7    20480.0      0.0     4480.0 866.3  384.0   73.9       0    0.000   0      0.000    0.000

それにしても、なぜマップ可能な領域を2GBの制限を設けたのだろうか。
また、明示的なアンマップ方法が無いのも扱いが難しい。DirectByteBufferの注意点とパフォーマンス比較でも解放の記述がある。

参考

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8