From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Wed, 6 May 2020 23:30:30 -0400 Subject: [PATCH] Optimize NibbleArray to use pooled buffers Massively reduces memory allocation of 2048 byte buffers by using an object pool for these. diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java index fa893b14bcef9bab6891dea2c4375b09d74ac038..738f5b975697cd83f1ff35eb0d2d8619ee8d39e4 100644 --- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java @@ -387,11 +387,11 @@ public class ChunkRegionLoader { } if (nibblearray != null && !nibblearray.c()) { - nbttagcompound2.setByteArray("BlockLight", nibblearray.asBytes()); + nbttagcompound2.setByteArray("BlockLight", nibblearray.getIfSet()); // Paper } if (nibblearray1 != null && !nibblearray1.c()) { - nbttagcompound2.setByteArray("SkyLight", nibblearray1.asBytes()); + nbttagcompound2.setByteArray("SkyLight", nibblearray1.getIfSet()); // Paper } nbttaglist.add(nbttagcompound2); diff --git a/src/main/java/net/minecraft/server/LightEngineStorageSky.java b/src/main/java/net/minecraft/server/LightEngineStorageSky.java index 06bc8371fe9de4d23fdd47e5a3919541bb399fd8..bf37e4ec1f3f4f73c27e1eecffa96423f683a10b 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorageSky.java +++ b/src/main/java/net/minecraft/server/LightEngineStorageSky.java @@ -166,7 +166,7 @@ public class LightEngineStorageSky extends LightEngineStorage BYTE_2048 = new PooledObjects<>(() -> new byte[2048], 16384, 1); + public static void releaseBytes(byte[] bytes) { + if (bytes != EMPTY_NIBBLE) { + System.arraycopy(EMPTY_NIBBLE, 0, bytes, 0, 2048); + BYTE_2048.release(bytes); + } + } + + public byte[] getIfSet() { + return this.a != null ? this.a : EMPTY_NIBBLE; + } + public byte[] getCloneIfSet() { + if (a == null) { + return EMPTY_NIBBLE; + } + byte[] ret = BYTE_2048.acquire(); + System.arraycopy(getIfSet(), 0, ret, 0, 2048); + return ret; + } + + @Override + protected void finalize() throws Throwable { + try { + if (this.a != null) { + releaseBytes(this.a); + this.a = null; + } + } finally { + super.finalize(); + } + } + // Paper end + @Nullable protected byte[] a; + public NibbleArray() {} public NibbleArray(byte[] abyte) { + // Paper start + this(abyte, false); + } + public NibbleArray(byte[] abyte, boolean isSafe) { this.a = abyte; + if (!isSafe) this.a = getCloneIfSet(); // Paper - clone for safety + // Paper end if (abyte.length != 2048) { throw (IllegalArgumentException) SystemUtils.c(new IllegalArgumentException("ChunkNibbleArrays should be 2048 bytes not: " + abyte.length)); } @@ -44,7 +86,7 @@ public class NibbleArray { public void a(int i, int j) { // PAIL: private -> public if (this.a == null) { - this.a = new byte[2048]; + this.a = BYTE_2048.acquire(); // Paper } int k = this.d(i); @@ -65,7 +107,7 @@ public class NibbleArray { public byte[] asBytes() { if (this.a == null) { - this.a = new byte[2048]; + this.a = BYTE_2048.acquire(); // Paper } return this.a; @@ -73,7 +115,7 @@ public class NibbleArray { public NibbleArray copy() { return this.b(); } // Paper - OBFHELPER public NibbleArray b() { - return this.a == null ? new NibbleArray() : new NibbleArray((byte[]) this.a.clone()); + return this.a == null ? new NibbleArray() : new NibbleArray(this.a); // Paper - clone in ctor } public String toString() { diff --git a/src/main/java/net/minecraft/server/NibbleArrayFlat.java b/src/main/java/net/minecraft/server/NibbleArrayFlat.java index 67c960292db9d99ac85b5d0dda50ae48ef942c1b..f7641156beea365a91a935667abf8c9539896dc0 100644 --- a/src/main/java/net/minecraft/server/NibbleArrayFlat.java +++ b/src/main/java/net/minecraft/server/NibbleArrayFlat.java @@ -18,7 +18,7 @@ public class NibbleArrayFlat extends NibbleArray { @Override public byte[] asBytes() { - byte[] abyte = new byte[2048]; + byte[] abyte = BYTE_2048.acquire(); // Paper for (int i = 0; i < 16; ++i) { System.arraycopy(this.a, 0, abyte, i * 128, 128); diff --git a/src/main/java/net/minecraft/server/PacketPlayOutLightUpdate.java b/src/main/java/net/minecraft/server/PacketPlayOutLightUpdate.java index cd1ad45469aa163b9bc41774ae80adfa617fd97b..d6560f4693869a6638963867f7ebc63bf80d534e 100644 --- a/src/main/java/net/minecraft/server/PacketPlayOutLightUpdate.java +++ b/src/main/java/net/minecraft/server/PacketPlayOutLightUpdate.java @@ -17,6 +17,15 @@ public class PacketPlayOutLightUpdate implements Packet { private List h; public PacketPlayOutLightUpdate() {} + // Paper start + private final java.util.List usedBytes = new java.util.ArrayList<>(); + + @Override + public void onPacketDone() { + usedBytes.forEach(NibbleArray::releaseBytes); + usedBytes.clear(); + } + // Paper end public PacketPlayOutLightUpdate(ChunkCoordIntPair chunkcoordintpair, LightEngine lightengine) { this.a = chunkcoordintpair.x; @@ -24,6 +33,7 @@ public class PacketPlayOutLightUpdate implements Packet { this.g = Lists.newArrayList(); this.h = Lists.newArrayList(); + byte[] lastBytes; // Paper for (int i = 0; i < 18; ++i) { NibbleArray nibblearray = lightengine.a(EnumSkyBlock.SKY).a(SectionPosition.a(chunkcoordintpair, -1 + i)); NibbleArray nibblearray1 = lightengine.a(EnumSkyBlock.BLOCK).a(SectionPosition.a(chunkcoordintpair, -1 + i)); @@ -33,7 +43,7 @@ public class PacketPlayOutLightUpdate implements Packet { this.e |= 1 << i; } else { this.c |= 1 << i; - this.g.add(nibblearray.asBytes().clone()); + this.g.add(lastBytes = nibblearray.getCloneIfSet()); usedBytes.add(lastBytes); // Paper } } @@ -42,7 +52,7 @@ public class PacketPlayOutLightUpdate implements Packet { this.f |= 1 << i; } else { this.d |= 1 << i; - this.h.add(nibblearray1.asBytes().clone()); + this.h.add(lastBytes = nibblearray1.getCloneIfSet()); usedBytes.add(lastBytes); // Paper } } } @@ -57,13 +67,14 @@ public class PacketPlayOutLightUpdate implements Packet { this.g = Lists.newArrayList(); this.h = Lists.newArrayList(); + byte[] lastBytes; // Paper for (int k = 0; k < 18; ++k) { NibbleArray nibblearray; if ((this.c & 1 << k) != 0) { nibblearray = lightengine.a(EnumSkyBlock.SKY).a(SectionPosition.a(chunkcoordintpair, -1 + k)); if (nibblearray != null && !nibblearray.c()) { - this.g.add(nibblearray.asBytes().clone()); + this.g.add(lastBytes = nibblearray.getCloneIfSet()); usedBytes.add(lastBytes); // Paper } else { this.c &= ~(1 << k); if (nibblearray != null) { @@ -75,7 +86,7 @@ public class PacketPlayOutLightUpdate implements Packet { if ((this.d & 1 << k) != 0) { nibblearray = lightengine.a(EnumSkyBlock.BLOCK).a(SectionPosition.a(chunkcoordintpair, -1 + k)); if (nibblearray != null && !nibblearray.c()) { - this.h.add(nibblearray.asBytes().clone()); + this.h.add(lastBytes = nibblearray.getCloneIfSet()); usedBytes.add(lastBytes); // Paper } else { this.d &= ~(1 << k); if (nibblearray != null) {