2020-05-06 17:48:49 +08:00
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
2020-05-04 13:03:57 +08:00
|
|
|
From: Aikar <aikar@aikar.co>
|
|
|
|
Date: Mon, 4 May 2020 00:38:13 -0400
|
|
|
|
Subject: [PATCH] Cleanup Region Files Direct Memory on close
|
|
|
|
|
|
|
|
Mojang was semi leaking native memory here by relying on finalizers
|
|
|
|
to clean up the direct memory.
|
|
|
|
|
|
|
|
Finalizers have no guarantee on when they will be ran, and since this is
|
|
|
|
old generation memory, it might be a while before its called.
|
|
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
|
2020-05-06 17:48:49 +08:00
|
|
|
index df728e2c0a2bf660a91e0bd6342c4b4b1471dcb7..20927d55c6700f66f0931bfe3d20fd8959c87989 100644
|
2020-05-04 13:03:57 +08:00
|
|
|
--- a/src/main/java/net/minecraft/server/RegionFile.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/RegionFile.java
|
|
|
|
@@ -30,7 +30,7 @@ public class RegionFile implements AutoCloseable {
|
|
|
|
private final FileChannel dataFile;
|
|
|
|
private final java.nio.file.Path d;
|
|
|
|
private final RegionFileCompression e;
|
|
|
|
- private final ByteBuffer f;
|
|
|
|
+ private final ByteBuffer f; private ByteBuffer getFileBuffer() { return f; } // Paper - clean up direct buffers on close
|
|
|
|
private final IntBuffer g;
|
|
|
|
private final IntBuffer h;
|
|
|
|
private final RegionFileBitSet freeSectors;
|
2020-05-04 14:19:38 +08:00
|
|
|
@@ -403,10 +403,59 @@ public class RegionFile implements AutoCloseable {
|
2020-05-04 13:03:57 +08:00
|
|
|
}
|
|
|
|
} finally { // Paper start - Prevent regionfiles from being closed during use
|
|
|
|
this.fileLock.unlock();
|
2020-05-04 14:19:38 +08:00
|
|
|
+ if (getFileBuffer().isDirect()) cleanDirectByteBuffer(getFileBuffer()); // Paper - clean up direct buffers on close
|
2020-05-04 13:03:57 +08:00
|
|
|
}
|
|
|
|
} // Paper end
|
|
|
|
|
2020-05-04 14:19:38 +08:00
|
|
|
}
|
|
|
|
+ // Paper start
|
|
|
|
+ private static int getVersion() {
|
|
|
|
+ String version = System.getProperty("java.version");
|
|
|
|
+ if(version.startsWith("1.")) {
|
|
|
|
+ version = version.substring(2, 3);
|
|
|
|
+ } else {
|
|
|
|
+ int dot = version.indexOf(".");
|
|
|
|
+ if(dot != -1) { version = version.substring(0, dot); }
|
|
|
|
+ } return Integer.parseInt(version);
|
|
|
|
+ }
|
|
|
|
+ static java.lang.reflect.Method unsafeClean;
|
|
|
|
+ static sun.misc.Unsafe unsafe = com.destroystokyo.paper.utils.UnsafeUtils.getUnsafe();
|
|
|
|
+ static java.util.function.Consumer<ByteBuffer> cleaner;
|
|
|
|
+ static {
|
|
|
|
+ try {
|
|
|
|
+ if (unsafe != null) {
|
|
|
|
+ unsafeClean = unsafe.getClass().getMethod("invokeCleaner", ByteBuffer.class);
|
|
|
|
+ if (unsafeClean != null) {
|
|
|
|
+ cleaner = (buf) -> {
|
|
|
|
+ try {
|
|
|
|
+ unsafeClean.invoke(unsafe, buf);
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ex);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ LOGGER.info("[RegionFile] Using Java 9+ invokeCleaner DirectByteBuffer cleanup method");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (java.lang.NoSuchMethodException e) {}
|
|
|
|
+ if (cleaner == null && getVersion() <= 8) {
|
|
|
|
+ cleaner = (buf) -> {
|
|
|
|
+ ((sun.nio.ch.DirectBuffer) buf).cleaner().clean();
|
|
|
|
+ };
|
|
|
|
+ LOGGER.info("[RegionFile] Using Java 8 DirectByteBuffer cleanup method");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ public static void cleanDirectByteBuffer(ByteBuffer toBeDestroyed) {
|
|
|
|
+ try {
|
|
|
|
+ if (cleaner != null) {
|
|
|
|
+ cleaner.accept(toBeDestroyed);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
+ LOGGER.warn("Failed automatically cleaning DirectByteBuffer");
|
|
|
|
+ ex.printStackTrace();
|
|
|
|
+ cleaner = null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Paper end
|
|
|
|
|
|
|
|
private void c() throws IOException {
|
|
|
|
int i = (int) this.dataFile.size();
|