Unverified 提交 7e3ef0c6 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1312 from katzyn/munmap

Add Java 9+ support to NIO_CLEANER_HACK
...@@ -9,7 +9,6 @@ import java.io.EOFException; ...@@ -9,7 +9,6 @@ import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.nio.BufferUnderflowException; import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer; import java.nio.MappedByteBuffer;
...@@ -19,6 +18,7 @@ import java.nio.channels.NonWritableChannelException; ...@@ -19,6 +18,7 @@ import java.nio.channels.NonWritableChannelException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.util.MemoryUnmapper;
/** /**
* This file system stores files on disk and uses java.nio to access the files. * This file system stores files on disk and uses java.nio to access the files.
...@@ -78,26 +78,13 @@ class FileNioMapped extends FileBase { ...@@ -78,26 +78,13 @@ class FileNioMapped extends FileBase {
// need to dispose old direct buffer, see bug // need to dispose old direct buffer, see bug
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
boolean useSystemGc = true;
if (SysProperties.NIO_CLEANER_HACK) { if (SysProperties.NIO_CLEANER_HACK) {
try { if (MemoryUnmapper.unmap(mapped)) {
Method cleanerMethod = mapped.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object cleaner = cleanerMethod.invoke(mapped);
if (cleaner != null) {
Method clearMethod = cleaner.getClass().getMethod("clean");
clearMethod.invoke(cleaner);
}
useSystemGc = false;
} catch (Throwable e) {
// useSystemGc is already true
} finally {
mapped = null; mapped = null;
return;
} }
} }
if (useSystemGc) { WeakReference<MappedByteBuffer> bufferWeakRef = new WeakReference<>(mapped);
WeakReference<MappedByteBuffer> bufferWeakRef =
new WeakReference<>(mapped);
mapped = null; mapped = null;
long start = System.nanoTime(); long start = System.nanoTime();
while (bufferWeakRef.get() != null) { while (bufferWeakRef.get() != null) {
...@@ -109,7 +96,6 @@ class FileNioMapped extends FileBase { ...@@ -109,7 +96,6 @@ class FileNioMapped extends FileBase {
Thread.yield(); Thread.yield();
} }
} }
}
/** /**
* Re-map byte buffer into memory, called when file size has changed or file * Re-map byte buffer into memory, called when file size has changed or file
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import org.h2.engine.SysProperties;
/**
* Unsafe memory unmapper.
*
* @see SysProperties#NIO_CLEANER_HACK
*/
public final class MemoryUnmapper {
private static final boolean ENABLED;
private static final Object UNSAFE;
private static final Method INVOKE_CLEANER;
static {
boolean enabled = SysProperties.NIO_CLEANER_HACK;
Object unsafe = null;
Method invokeCleaner = null;
if (enabled) {
try {
Class<?> clazz = Class.forName("sun.misc.Unsafe");
Field field = clazz.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = field.get(null);
// This method exists only on Java 9 and later versions
invokeCleaner = clazz.getMethod("invokeCleaner", ByteBuffer.class);
} catch (ReflectiveOperationException e) {
// Java 7 or 8
unsafe = null;
// invokeCleaner can be only null here
} catch (Throwable e) {
// Should be a SecurityException, but catch everything to be
// safe
enabled = false;
unsafe = null;
// invokeCleaner can be only null here
}
}
ENABLED = enabled;
UNSAFE = unsafe;
INVOKE_CLEANER = invokeCleaner;
}
/**
* Tries to unmap memory for the specified byte buffer using Java internals
* in unsafe way if {@link SysProperties#NIO_CLEANER_HACK} is enabled and
* access is not denied by a security manager.
*
* @param buffer
* mapped byte buffer
* @return whether operation was successful
*/
public static boolean unmap(ByteBuffer buffer) {
if (!ENABLED) {
return false;
}
try {
if (INVOKE_CLEANER != null) {
// Java 9 or later
INVOKE_CLEANER.invoke(UNSAFE, buffer);
return true;
}
// Java 7 or 8
Method cleanerMethod = buffer.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object cleaner = cleanerMethod.invoke(buffer);
if (cleaner != null) {
Method clearMethod = cleaner.getClass().getMethod("clean");
clearMethod.invoke(cleaner);
}
return true;
} catch (Throwable e) {
return false;
}
}
private MemoryUnmapper() {
}
}
...@@ -193,6 +193,7 @@ import org.h2.test.unit.TestIntPerfectHash; ...@@ -193,6 +193,7 @@ import org.h2.test.unit.TestIntPerfectHash;
import org.h2.test.unit.TestJmx; import org.h2.test.unit.TestJmx;
import org.h2.test.unit.TestLocale; import org.h2.test.unit.TestLocale;
import org.h2.test.unit.TestMathUtils; import org.h2.test.unit.TestMathUtils;
import org.h2.test.unit.TestMemoryUnmapper;
import org.h2.test.unit.TestMode; import org.h2.test.unit.TestMode;
import org.h2.test.unit.TestModifyOnWrite; import org.h2.test.unit.TestModifyOnWrite;
import org.h2.test.unit.TestNetUtils; import org.h2.test.unit.TestNetUtils;
...@@ -960,6 +961,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -960,6 +961,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestIntIntHashMap()); addTest(new TestIntIntHashMap());
addTest(new TestIntPerfectHash()); addTest(new TestIntPerfectHash());
addTest(new TestMathUtils()); addTest(new TestMathUtils());
addTest(new TestMemoryUnmapper());
addTest(new TestMode()); addTest(new TestMode());
addTest(new TestObjectDeserialization()); addTest(new TestObjectDeserialization());
addTest(new TestOverflow()); addTest(new TestOverflow());
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.unit;
import java.lang.ProcessBuilder.Redirect;
import java.nio.ByteBuffer;
import org.h2.test.TestBase;
import org.h2.util.MemoryUnmapper;
/**
* Tests memory unmapper.
*/
public class TestMemoryUnmapper extends TestBase {
private static final int OK = 0, /* EXCEPTION = 1, */ UNAVAILABLE = 2;
/**
* May be used to run only this test and may be launched by this test in a
* subprocess.
*
* @param a
* if empty run this test only
*/
public static void main(String... a) throws Exception {
if (a.length == 0) {
TestBase.createCaller().init().test();
} else {
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
System.exit(MemoryUnmapper.unmap(buffer) ? OK : UNAVAILABLE);
}
}
@Override
public void test() throws Exception {
ProcessBuilder pb = new ProcessBuilder().redirectError(Redirect.INHERIT);
// Test that unsafe unmapping is disabled by default
pb.command(getJVM(), "-cp", getClassPath(), "-ea", getClass().getName(), "dummy");
assertEquals(UNAVAILABLE, pb.start().waitFor());
// Test that it can be enabled
pb.command(getJVM(), "-cp", getClassPath(), "-ea", "-Dh2.nioCleanerHack=true", getClass().getName(), "dummy");
assertEquals(OK, pb.start().waitFor());
// Test that it will not be enabled with a security manager
pb.command(getJVM(), "-cp", getClassPath(), "-ea", "-Djava.security.manager", "-Dh2.nioCleanerHack=true",
getClass().getName(), "dummy");
assertEquals(UNAVAILABLE, pb.start().waitFor());
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论