diff --git a/core/java/src/net/i2p/crypto/YKGenerator.java b/core/java/src/net/i2p/crypto/YKGenerator.java
index 75f21a50e8cf4b7c174a567c06076f1b49279b3c..3b23c4df51e9d328ccade09c4d69e6860dc11d08 100644
--- a/core/java/src/net/i2p/crypto/YKGenerator.java
+++ b/core/java/src/net/i2p/crypto/YKGenerator.java
@@ -15,6 +15,7 @@ import java.util.concurrent.LinkedBlockingQueue;
 import net.i2p.I2PAppContext;
 import net.i2p.util.I2PThread;
 import net.i2p.util.NativeBigInteger;
+import net.i2p.util.SystemVersion;
 
 /**
  * Precalculate the Y and K for ElGamal encryption operations.
@@ -55,9 +56,7 @@ class YKGenerator {
         ctx = context;
 
         // add to the defaults for every 128MB of RAM, up to 1GB
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 127*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         int factor = (int) Math.max(1l, Math.min(8l, 1 + (maxMemory / (128*1024*1024l))));
         int defaultMin = DEFAULT_YK_PRECALC_MIN * factor;
         int defaultMax = DEFAULT_YK_PRECALC_MAX * factor;
diff --git a/core/java/src/net/i2p/data/RouterInfo.java b/core/java/src/net/i2p/data/RouterInfo.java
index b6234d7ad8344bb302640df420ff3a373c9416ca..4199d0ee93674b817b824b877a9871ce07313e3b 100644
--- a/core/java/src/net/i2p/data/RouterInfo.java
+++ b/core/java/src/net/i2p/data/RouterInfo.java
@@ -33,6 +33,7 @@ import net.i2p.crypto.SHA256Generator;
 import net.i2p.util.Clock;
 import net.i2p.util.Log;
 import net.i2p.util.OrderedProperties;
+import net.i2p.util.SystemVersion;
 
 /**
  * Defines the data that a router either publishes to the global routing table or
@@ -68,8 +69,7 @@ public class RouterInfo extends DatabaseEntry {
     /** should we cache the byte and string versions _byteified ? **/
     private boolean _shouldCache;
     /** maybe we should check if we are floodfill? */
-    private static final boolean CACHE_ALL = Runtime.getRuntime().maxMemory() > 128*1024*1024l &&
-                                             Runtime.getRuntime().maxMemory() < Long.MAX_VALUE;
+    private static final boolean CACHE_ALL = SystemVersion.getMaxMemory() > 128*1024*1024l;
 
     public static final String PROP_NETWORK_ID = "netId";
     public static final String PROP_CAPABILITIES = "caps";
diff --git a/core/java/src/net/i2p/data/SDSCache.java b/core/java/src/net/i2p/data/SDSCache.java
index 0c635084dbf58ae40401279952bf213040558958..b31f5b14c73098fbb3df5ebb011a3f6999e3d2ea 100644
--- a/core/java/src/net/i2p/data/SDSCache.java
+++ b/core/java/src/net/i2p/data/SDSCache.java
@@ -11,6 +11,7 @@ import java.util.Map;
 import net.i2p.I2PAppContext;
 import net.i2p.util.LHMCache;
 import net.i2p.util.SimpleByteCache;
+import net.i2p.util.SystemVersion;
 
 /**
  *  A least recently used cache with a max size, for SimpleDataStructures.
@@ -49,9 +50,7 @@ public class SDSCache<V extends SimpleDataStructure> {
     private static final double MAX_FACTOR = 5.0;
     private static final double FACTOR;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         FACTOR = Math.max(MIN_FACTOR, Math.min(MAX_FACTOR, maxMemory / (128*1024*1024d)));
     }
 
diff --git a/core/java/src/net/i2p/util/Addresses.java b/core/java/src/net/i2p/util/Addresses.java
index 77e4759fa22cd4801481009a9c084e7852b5ce3c..03974441707c75b55cff6c3adbdd87a9de840a3c 100644
--- a/core/java/src/net/i2p/util/Addresses.java
+++ b/core/java/src/net/i2p/util/Addresses.java
@@ -228,9 +228,7 @@ public abstract class Addresses {
         int size;
         I2PAppContext ctx = I2PAppContext.getCurrentContext();
         if (ctx != null && ctx.isRouterContext()) {
-            long maxMemory = Runtime.getRuntime().maxMemory();
-            if (maxMemory == Long.MAX_VALUE)
-                maxMemory = 96*1024*1024l;
+            long maxMemory = SystemVersion.getMaxMemory();
             long min = 128;
             long max = 4096;
             // 512 nominal for 128 MB
diff --git a/core/java/src/net/i2p/util/ByteCache.java b/core/java/src/net/i2p/util/ByteCache.java
index b88a21c1412c30362c42fd7b5a2b3729ffe6c9a8..459b2fce4d462fd9592edfe7a2bcecad64f735ba 100644
--- a/core/java/src/net/i2p/util/ByteCache.java
+++ b/core/java/src/net/i2p/util/ByteCache.java
@@ -62,9 +62,7 @@ public final class ByteCache {
      */
     private static final int MAX_CACHE;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         MAX_CACHE = (int) Math.min(4*1024*1024l, Math.max(128*1024l, maxMemory / 128));
     }
 
diff --git a/core/java/src/net/i2p/util/SimpleScheduler.java b/core/java/src/net/i2p/util/SimpleScheduler.java
index f0cade14c0c8ef7a2a75b6167f04ad5f893ad6b1..5123f5884c6bd3b358ee6260d3a920f49c08742b 100644
--- a/core/java/src/net/i2p/util/SimpleScheduler.java
+++ b/core/java/src/net/i2p/util/SimpleScheduler.java
@@ -58,9 +58,7 @@ public class SimpleScheduler {
     private SimpleScheduler(I2PAppContext context, String name) {
         _log = context.logManager().getLog(SimpleScheduler.class);
         _name = name;
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
         _executor = new ScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
         _executor.prestartAllCoreThreads();
diff --git a/core/java/src/net/i2p/util/SimpleTimer.java b/core/java/src/net/i2p/util/SimpleTimer.java
index 181d01ffbdb07050a9e96fb823e3ac8810e5a1da..c3ef807aded966d212292aed53580c0df755d178 100644
--- a/core/java/src/net/i2p/util/SimpleTimer.java
+++ b/core/java/src/net/i2p/util/SimpleTimer.java
@@ -61,9 +61,7 @@ public class SimpleTimer {
         runner.setName(name);
         runner.setDaemon(true);
         runner.start();
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 128*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         int threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
         for (int i = 1; i <= threads ; i++) {
             I2PThread executor = new I2PThread(new Executor(context, _log, _readyEvents, runn));
diff --git a/core/java/src/net/i2p/util/SimpleTimer2.java b/core/java/src/net/i2p/util/SimpleTimer2.java
index e22b6fb7092ecf428fe88df3935f7b125f36bb92..9526ef0693639a7a0111a76612ee2983c2bff8c2 100644
--- a/core/java/src/net/i2p/util/SimpleTimer2.java
+++ b/core/java/src/net/i2p/util/SimpleTimer2.java
@@ -64,9 +64,7 @@ public class SimpleTimer2 {
      */
     protected SimpleTimer2(I2PAppContext context, String name, boolean prestartAllThreads) {
         _name = name;
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
         _executor = new CustomScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
         if (prestartAllThreads)
diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java
index 4761731a85327e8c19a6b13ca6bcfc01be2169ec..eaca96e6230d07a1524cd2a77fbaa5ff85f1f610 100644
--- a/core/java/src/net/i2p/util/SystemVersion.java
+++ b/core/java/src/net/i2p/util/SystemVersion.java
@@ -126,4 +126,16 @@ public abstract class SystemVersion {
     public static boolean hasWrapper() {
         return _hasWrapper;
     }
+
+    /**
+     *  Runtime.getRuntime().maxMemory() but check for
+     *  bogus values
+     *  @since 0.9.8
+     */
+    public static long getMaxMemory() {
+        long maxMemory = Runtime.getRuntime().maxMemory();
+        if (maxMemory >= Long.MAX_VALUE / 2)
+            maxMemory = 96*1024*1024l;
+        return maxMemory;
+    }
 }
diff --git a/router/java/src/net/i2p/router/JobQueue.java b/router/java/src/net/i2p/router/JobQueue.java
index dd13638e3781589b47a04b7e2856babcafeea5ea..b0630a8371e82a6b7805793d24bed564cc504bc5 100644
--- a/router/java/src/net/i2p/router/JobQueue.java
+++ b/router/java/src/net/i2p/router/JobQueue.java
@@ -27,6 +27,7 @@ import net.i2p.router.networkdb.kademlia.HandleFloodfillDatabaseLookupMessageJob
 import net.i2p.util.Clock;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Manage the pending jobs according to whatever algorithm is appropriate, giving
@@ -60,9 +61,7 @@ public class JobQueue {
     /** how many when we go parallel */
     private static final int RUNNERS;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 128*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         if (maxMemory < 64*1024*1024)
             RUNNERS = 3;
         else if (maxMemory < 256*1024*1024)
diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java
index 5101076a8c96454c8474f42c5f43a4008cc406dd..0fbb2a6f602343f2e7b6bdeab95394fdb2d8057d 100644
--- a/router/java/src/net/i2p/router/RouterContext.java
+++ b/router/java/src/net/i2p/router/RouterContext.java
@@ -27,6 +27,7 @@ import net.i2p.router.tunnel.pool.TunnelPoolManager;
 import net.i2p.update.UpdateManager;
 import net.i2p.util.KeyRing;
 import net.i2p.util.I2PProperties.I2PPropertyCallback;
+import net.i2p.util.SystemVersion;
 
 /**
  * Build off the core I2P context to provide a root for a router instance to
@@ -114,9 +115,7 @@ public class RouterContext extends I2PAppContext {
             // and prng.bufferFillTime event count is ~30 per minute,
             // or about 2 seconds per buffer - so about 200x faster
             // to fill than to drain - so we don't need too many
-            long maxMemory = Runtime.getRuntime().maxMemory();
-            if (maxMemory == Long.MAX_VALUE)
-                maxMemory = 96*1024*1024l;
+            long maxMemory = SystemVersion.getMaxMemory();
             long buffs = Math.min(16, Math.max(2, maxMemory / (14 * 1024 * 1024)));
             envProps.setProperty("prng.buffers", "" + buffs);
         }
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java
index 3a058fc78afbbada42f3bb27bc2179c4adc16ac6..e124e19d51f0f80caa5fda1673196c9e16044b84 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java
@@ -20,6 +20,7 @@ import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  *  The network database
@@ -417,9 +418,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad
     /** @since 0.8.7 */
     private static final int MAX_DB_BEFORE_SKIPPING_SEARCH;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 128*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         // 250 for every 32 MB, min of 250, max of 1250
         MAX_DB_BEFORE_SKIPPING_SEARCH = (int) Math.max(250l, Math.min(1250l, maxMemory / ((32 * 1024 * 1024l) / 250)));
     }
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index 251200f34c91bec856a6d6d319c6e2ef497b27fb..19873cc6d4a923c8284ac060e538687febe40797 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -67,9 +67,7 @@ public abstract class TransportImpl implements Transport {
     private static final Map<Hash, byte[]> _IPMap;
 
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         long min = 512;
         long max = 4096;
         // 1024 nominal for 128 MB
diff --git a/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java b/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java
index 23f52aef39b952a8114d2df442bb3df476469b86..36911b67a0ef012203526a8031635ca915bfc1da 100644
--- a/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java
+++ b/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java
@@ -26,6 +26,7 @@ import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
 import net.i2p.util.NativeBigInteger;
 import net.i2p.util.RandomSource;
+import net.i2p.util.SystemVersion;
 
 /**
  * Generate a new session key through a diffie hellman exchange.  This uses the
@@ -458,9 +459,7 @@ public class DHSessionKeyBuilder {
             ctx.statManager().createRateStat("crypto.DHEmpty", "DH queue empty", "Encryption", new long[] { 60*60*1000 });
 
             // add to the defaults for every 128MB of RAM, up to 512MB
-            long maxMemory = Runtime.getRuntime().maxMemory();
-            if (maxMemory == Long.MAX_VALUE)
-                maxMemory = 127*1024*1024l;
+            long maxMemory = SystemVersion.getMaxMemory();
             int factor = (int) Math.max(1l, Math.min(4l, 1 + (maxMemory / (128*1024*1024l))));
             int defaultMin = DEFAULT_DH_PRECALC_MIN * factor;
             int defaultMax = DEFAULT_DH_PRECALC_MAX * factor;
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
index d03666c5a092ff65d301c232ac0d6fa532ebcd71..2960c844b94891568258366633dbf6353066888b 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
@@ -29,6 +29,7 @@ import net.i2p.util.Addresses;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  *  The main NTCP NIO thread.
@@ -90,9 +91,7 @@ class EventPumper implements Runnable {
     private static final int MAX_MINB = 12;
     private static final int MIN_BUFS;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         MIN_BUFS = (int) Math.max(MIN_MINB, Math.min(MAX_MINB, 1 + (maxMemory / (16*1024*1024))));
     }
 
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
index 38f8a29d77dec4e072a05bf1c4ca611cad142730..ff61536455546f81d4b6abae35bec1b211bdef21 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
@@ -35,6 +35,7 @@ import net.i2p.util.ByteCache;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.HexDump;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Coordinate the connection to a single peer.
@@ -840,9 +841,7 @@ class NTCPConnection {
     private static final int MAX_BUFS = 16;
     private static int NUM_PREP_BUFS;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         NUM_PREP_BUFS = (int) Math.max(MIN_BUFS, Math.min(MAX_BUFS, 1 + (maxMemory / (16*1024*1024))));
     }
 
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java
index e6bea5c2e466c3cdd0512dfcb5921c5e8c5fc602..cdaec194784224811710b0822c074e4a076b90cb 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java
@@ -10,6 +10,7 @@ import java.util.concurrent.ThreadFactory;
 import net.i2p.I2PAppContext;
 import net.i2p.router.OutNetMessage;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Previously, NTCP was using SimpleTimer with a delay of 0, which
@@ -33,9 +34,7 @@ class NTCPSendFinisher {
     private ThreadPoolExecutor _executor;
     private static final int THREADS;
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         THREADS = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
     }
 
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index cb504a747beb65bd73f905668cac0ce3a1583104..1a8c9c35d98d723b42d7c2ac58996080db20fdee 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -44,6 +44,7 @@ import net.i2p.util.Addresses;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.Log;
 import net.i2p.util.OrderedProperties;
+import net.i2p.util.SystemVersion;
 
 /**
  *  The NIO TCP transport
@@ -571,9 +572,7 @@ public class NTCPTransport extends TransportImpl {
         _finisher.start();
         _pumper.startPumping();
 
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 128*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         int nr, nw;
         if (maxMemory < 32*1024*1024) {
             nr = nw = 1;
diff --git a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java
index cb32ac013e3c0264893360c021e6f8c529eddc0e..c0fa2eea2ba0921baeb948df4195bf1fac746e5e 100644
--- a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java
+++ b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java
@@ -14,6 +14,7 @@ import net.i2p.router.util.CoDelBlockingQueue;
 import net.i2p.util.HexDump;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Pull fully completed fragments off the {@link InboundMessageFragments} queue,
@@ -41,9 +42,7 @@ class MessageReceiver {
         _log = ctx.logManager().getLog(MessageReceiver.class);
         _transport = transport;
 
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         int qsize;
         if (maxMemory < 32*1024*1024) {
             _threadCount = 1;
diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
index e901ac859506adae016259d214cfde04c0b24a04..5a9c6eaf65e2a7d427a3fb83f2877ef3ea71f11b 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
@@ -12,6 +12,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.util.I2PThread;
 import net.i2p.util.LHMCache;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Pull inbound packets from the inbound receiver's queue, figure out what
@@ -57,9 +58,7 @@ class PacketHandler {
         _introManager = introManager;
         _failCache = new LHMCache(24);
 
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         int qsize = (int) Math.max(MIN_QUEUE_SIZE, Math.min(MAX_QUEUE_SIZE, maxMemory / (2*1024*1024)));
         _inboundQueue = new CoDelBlockingQueue(ctx, "UDP-Receiver", qsize);
         int num_handlers;
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPAddress.java b/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
index 55fa9788d1d4b503de74d27102be1fbda739bef2..962ad31fad85ebf0fc3f1b976d97e73860aaa00f 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
@@ -8,6 +8,7 @@ import net.i2p.data.Base64;
 import net.i2p.data.RouterAddress;
 import net.i2p.data.SessionKey;
 import net.i2p.util.LHMCache;
+import net.i2p.util.SystemVersion;
 
 /**
  * basic helper to parse out peer info from a udp address
@@ -223,9 +224,7 @@ class UDPAddress {
     private static final Map<String, InetAddress> _inetAddressCache;
 
     static {
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         long min = 128;
         long max = 2048;
         // 512 nominal for 128 MB
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java
index 8c13a57b7bf40a50bca6e3190eb521572f2e98ee..741aad8cae3e6247ab308eab8f6e0c6f7fa00ca5 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java
@@ -12,6 +12,7 @@ import net.i2p.data.SessionKey;
 import net.i2p.router.util.CDQEntry;
 import net.i2p.util.Addresses;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Basic delivery unit containing the datagram.  This also maintains a cache
@@ -48,9 +49,7 @@ class UDPPacket implements CDQEntry {
     private static final int MAX_CACHE_SIZE = 256;
     static {
         if (CACHE) {
-            long maxMemory = Runtime.getRuntime().maxMemory();
-            if (maxMemory == Long.MAX_VALUE)
-                maxMemory = 96*1024*1024l;
+            long maxMemory = SystemVersion.getMaxMemory();
             int csize = (int) Math.max(MIN_CACHE_SIZE, Math.min(MAX_CACHE_SIZE, maxMemory / (1024*1024)));
             _packetCache = new LinkedBlockingQueue(csize);
         } else {
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPSender.java b/router/java/src/net/i2p/router/transport/udp/UDPSender.java
index aa1affbb575e1111abe8df05e04fba7e333f88ed..c5aecf62727568be139dbc8ed1bb36bbbc0a9137 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPSender.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPSender.java
@@ -10,6 +10,7 @@ import net.i2p.router.transport.FIFOBandwidthLimiter;
 import net.i2p.router.util.CoDelBlockingQueue;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Lowest level packet sender, pushes anything on its queue ASAP.
@@ -37,9 +38,7 @@ class UDPSender {
         _context = ctx;
         _dummy = false; // ctx.commSystem().isDummy();
         _log = ctx.logManager().getLog(UDPSender.class);
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         int qsize = (int) Math.max(MIN_QUEUE_SIZE, Math.min(MAX_QUEUE_SIZE, maxMemory / (1024*1024)));
         _outboundQueue = new CoDelBlockingQueue(ctx, "UDP-Sender", qsize);
         _socket = socket;
diff --git a/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java b/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java
index 857c7fdecd846f9988e98bf4901fb5ac73cdf07f..c80f51f57c9e063bdbca4a801ac13f285c2e779b 100644
--- a/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java
+++ b/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java
@@ -6,6 +6,7 @@ import net.i2p.router.RouterContext;
 import net.i2p.router.util.DecayingBloomFilter;
 import net.i2p.router.util.DecayingHashSet;
 import net.i2p.util.SimpleByteCache;
+import net.i2p.util.SystemVersion;
 
 /**
  * Manage the IV validation for all of the router's tunnels by way of a big
@@ -38,9 +39,7 @@ class BloomFilterIVValidator implements IVValidator {
         // Note that at rates above 512KB, we increase the filter size
         // to keep acceptable false positive rates.
         // See DBF, BloomSHA1, and KeySelector for details.
-        long maxMemory = Runtime.getRuntime().maxMemory();
-        if (maxMemory == Long.MAX_VALUE)
-            maxMemory = 96*1024*1024l;
+        long maxMemory = SystemVersion.getMaxMemory();
         if (_context.getBooleanProperty(PROP_FORCE))
             _filter = new DecayingBloomFilter(ctx, HALFLIFE_MS, 16, "TunnelIVV");  // 2MB fixed
         else if (KBps < MIN_SHARE_KBPS_TO_USE_BLOOM || maxMemory < MIN_MEM_TO_USE_BLOOM)
diff --git a/router/java/src/net/i2p/router/tunnel/TunnelGatewayPumper.java b/router/java/src/net/i2p/router/tunnel/TunnelGatewayPumper.java
index 680a23966e62de414a7bc62a5b5bf9aee6c5d057..024b1072b1157cf98cee09a7f107837989365249 100644
--- a/router/java/src/net/i2p/router/tunnel/TunnelGatewayPumper.java
+++ b/router/java/src/net/i2p/router/tunnel/TunnelGatewayPumper.java
@@ -13,6 +13,7 @@ import net.i2p.router.RouterContext;
 import net.i2p.util.I2PThread;
 import net.i2p.util.SimpleScheduler;
 import net.i2p.util.SimpleTimer;
+import net.i2p.util.SystemVersion;
 
 /**
  * Run through the tunnel gateways that have had messages added to them and push
@@ -45,9 +46,7 @@ class TunnelGatewayPumper implements Runnable {
         if (ctx.getBooleanProperty("i2p.dummyTunnelManager")) {
             _pumpers = 1;
         } else {
-            long maxMemory = Runtime.getRuntime().maxMemory();
-            if (maxMemory == Long.MAX_VALUE)
-                maxMemory = 96*1024*1024l;
+            long maxMemory = SystemVersion.getMaxMemory();
             _pumpers = (int) Math.max(MIN_PUMPERS, Math.min(MAX_PUMPERS, 1 + (maxMemory / (32*1024*1024))));
         }
         for (int i = 0; i < _pumpers; i++)