Java: Why not use mapped files? Because they are unpredictable!

Usar ficheros mmapped en Java es en el mejor de los casos… un dolor de cabeza (a menos que uses una JVM de 64bits -en cuyo caso el problema queda camuflado-). Nada que ver con las llamadas en C que funcionan muy bien y son perfectamente predecibles. Ante la duda… principio de KiSS, si no lo necesitas, no lo uses, a la larga tu codigo se romperá menos.

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.Random;

/**
 * Why not use java mapped files? Because they are unpredictable!
 * <br/> In Windows:
 * <br/> 	java.lang.OutOfMemoryError: Map failed
 * <br/> In Linux:
 * <br/> 	can work, if you are lucky.
 */
public class TestMappedFile {
	private static final Random r = new Random();
	private static final long filesize = 128 * 1024 * 1024;

	public static void main(String[] args) throws Exception {
		try {
			for (int i = 1; i < 128; i++) {
				System.out.println("Creating: " + i + " with size " + filesize);
				create(i);
			}
		} catch (Throwable t) {
			// WTF? Yeah... mmap sucks
			t.printStackTrace(System.out);
		}
	}
	private static void create(final int i) throws IOException {
		final File file = new File("/tmp/mmap." + i + ".tmp");
		final RandomAccessFile raf = new RandomAccessFile(file, "rw");
		raf.setLength(filesize);
		MappedByteBuffer buf = null;
		try {
			final int offset = (r.nextInt() & 0xFFFF);
			final byte b = (byte) (r.nextInt() & 0xFF);
			final FileChannel channel = raf.getChannel();
			// Section of file to map
			buf = channel.map(MapMode.READ_WRITE, 0L, channel.size()-1);
			// do something with buf
			buf.clear();
			write(buf, 0, b);
			write(buf, offset, b);
			write(buf, buf.limit()-1, b);
			buf.force();
			channel.force(false);
		} finally {
			//unmapMmapedWithInternalSunAPI(buf); // Non-portable clean method
			// In theory: Mapping remains until file is closed
			raf.close();
			buf = null;
			if (!file.delete()) {
				System.out.println("WTF? Can not delete file " + file.getAbsolutePath());
			}
		}
	}
	private static void write(final ByteBuffer buf, final int offset, final byte b) {
		System.out.println("Writing " + b + " in offset " + offset + "/" + buf.limit());
		buf.put(offset, b);
	}
	// Can crash with: java.lang.Error: Cleaner terminated abnormally
	//private static void unmapMmapedWithInternalSunAPI(final ByteBuffer buf) {
	//	if ((buf != null) && (buf instanceof sun.nio.ch.DirectBuffer)) {
	//		final sun.misc.Cleaner cleaner = ((sun.nio.ch.DirectBuffer) buf).cleaner();
	//		cleaner.clean();
	//	}
	//}
}

Referencias:
Sun Bug
How unmap? You can’t

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: