J'ai étudié le comportement lorsque le mappage de fichiers est effectué en Java, je vais donc le résumer.
Environnement CentOS7.3.1611, openjdk-1.8.0.131
Vous pouvez utiliser l'appel système open + mMap en langage C pour mapper des fichiers à la mémoire, mais j'ai toujours été préoccupé par son utilisation en Java. Je vais vraiment l'essayer.
Évaluez avec les sources suivantes.
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);
}
}
Par ailleurs, dans le cas d'un fichier qui dépasse Integer.MAX_VALUE (2 ^ 31), l'erreur suivante se produira au moment de la mappe. J'ai pu cartographier avec une taille de 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
À ce stade, l'état de la mappe de mémoire du processus java et l'état de Java sont les suivants. Il semble être mappé avec mmap. D'après les résultats de jstat, il semble que la zone mappée soit hors du tas.
$ cat /proc/$(pidof java)/maps
(Abréviation)
7f97c8000000-7f9848000000 r--s 00000000 00:26 5 /mnt/hgfs/COMMON/Java_Mmap/2gb-1
(Abréviation)
$ 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
Les deux fichiers sont correctement mappés. Le tas n'a pas augmenté autant que la zone de lecture supplémentaire (2 ^ 31-2).
$ cat /proc/$(pidof java)/maps
(Abréviation)
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
(Abréviation)
$ 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
Même ainsi, pourquoi avons-nous fixé une limite de 2 Go sur la zone cartographiable? Il est également difficile à gérer car il n'existe pas de méthode de démappage explicite. Notes sur DirectByteBuffer et comparaison des performances a également une description de la version.