From 54d0b721c4e3eb65afb2d6c420928216e0078b19 Mon Sep 17 00:00:00 2001 From: catbref Date: Mon, 16 Mar 2020 17:50:49 +0000 Subject: [PATCH] Dynamically allocate/deallocate Peer byteBuffer to reduce memory load at the expense of extra GC --- src/main/java/org/qortal/network/Peer.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/qortal/network/Peer.java b/src/main/java/org/qortal/network/Peer.java index 34a4f570..41e19397 100644 --- a/src/main/java/org/qortal/network/Peer.java +++ b/src/main/java/org/qortal/network/Peer.java @@ -61,6 +61,8 @@ public class Peer { private InetSocketAddress resolvedAddress = null; /** True if remote address is loopback/link-local/site-local, false otherwise. */ private boolean isLocal; + + private final Object byteBufferLock = new Object(); private volatile ByteBuffer byteBuffer; private Map> replyQueues; private LinkedBlockingQueue pendingMessages; @@ -256,7 +258,7 @@ public class Peer { this.connectionTimestamp = NTP.getTime(); this.socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true); this.socketChannel.configureBlocking(false); - this.byteBuffer = ByteBuffer.allocate(Network.getInstance().getMaxMessageSize()); + this.byteBuffer = null; // Defer allocation to when we need it, to save memory. Sorry GC! this.replyQueues = Collections.synchronizedMap(new HashMap>()); this.pendingMessages = new LinkedBlockingQueue<>(); } @@ -292,11 +294,15 @@ public class Peer { * @throws IOException */ /* package */ void readChannel() throws IOException { - synchronized (this.byteBuffer) { + synchronized (this.byteBufferLock) { while(true) { if (!this.socketChannel.isOpen() || this.socketChannel.socket().isClosed()) return; + // Do we need to allocate byteBuffer? + if (this.byteBuffer == null) + this.byteBuffer = ByteBuffer.allocate(Network.getInstance().getMaxMessageSize()); + final int bytesRead = this.socketChannel.read(this.byteBuffer); if (bytesRead == -1) { this.disconnect("EOF"); @@ -318,9 +324,15 @@ public class Peer { return; } - if (message == null && bytesRead == 0 && !wasByteBufferFull) + if (message == null && bytesRead == 0 && !wasByteBufferFull) { // No complete message in buffer, no more bytes to read from socket even though there was room to read bytes + + // If byteBuffer is empty then we can deallocate it, to save memory, albeit costing GC + if (this.byteBuffer.remaining() == this.byteBuffer.capacity()) + this.byteBuffer = null; + return; + } if (message == null) // No complete message in buffer, but maybe more bytes to read from socket