package games.strategy.engine.framework.system; import java.util.Properties; import games.strategy.debug.ClientLogger; import games.strategy.engine.framework.GameRunner; public class Memory { public static final String TRIPLEA_MEMORY_SET = "triplea.memory.set"; private static final String TRIPLEA_MEMORY_ONLINE_ONLY = "triplea.memory.onlineOnly"; // what should our xmx be approximately? private static final String TRIPLEA_MEMORY_XMX = "triplea.memory.Xmx"; private static final String TRIPLEA_MEMORY_USE_DEFAULT = "triplea.memory.useDefault"; public static void checkForMemoryXMX() { final String memSetString = System.getProperty(TRIPLEA_MEMORY_SET, "false"); final boolean memSet = Boolean.parseBoolean(memSetString); // if we have already set the memory, then return. // (example: we used process runner to create a new triplea with a specific memory) if (memSet) { return; } final Properties systemIni = GameRunner.getSystemIni(); if (useDefaultMaxMemory(systemIni)) { return; } if (getUseMaxMemorySettingOnlyForOnlineJoinOrHost(systemIni)) { return; } long xmx = getMaxMemoryFromSystemIniFileInMB(systemIni); // if xmx less than zero, return (because it means we do not want to change it) if (xmx <= 0) { return; } final int mb = 1024 * 1024; xmx = xmx * mb; final long currentMaxMemory = Runtime.getRuntime().maxMemory(); System.out.println("Current max memory: " + currentMaxMemory + "; and new xmx should be: " + xmx); final long diff = Math.abs(currentMaxMemory - xmx); // Runtime.maxMemory is never accurate, and is usually off by 5% to 15%, // so if our difference is less than 22% we should just ignore the difference if (diff <= xmx * 0.22) { return; } // the difference is significant enough that we should re-run triplea with a larger number GameRunner.startNewTripleA(xmx); // must exit now System.exit(0); } public static boolean useDefaultMaxMemory(final Properties systemIni) { final String useDefaultMaxMemoryString = systemIni.getProperty(TRIPLEA_MEMORY_USE_DEFAULT, "true"); return Boolean.parseBoolean(useDefaultMaxMemoryString); } public static long getMaxMemoryInBytes() { final Properties systemIni = GameRunner.getSystemIni(); final String useDefaultMaxMemoryString = systemIni.getProperty(TRIPLEA_MEMORY_USE_DEFAULT, "true"); final boolean useDefaultMaxMemory = Boolean.parseBoolean(useDefaultMaxMemoryString); final String maxMemoryString = systemIni.getProperty(TRIPLEA_MEMORY_XMX, "").trim(); // for whatever reason, .maxMemory() returns a value about 12% smaller than the real Xmx value. // Just something to be aware of. long max = Runtime.getRuntime().maxMemory(); if (!useDefaultMaxMemory && maxMemoryString.length() > 0) { try { final int maxMemorySet = Integer.parseInt(maxMemoryString); // it is in MB max = 1024 * 1024 * ((long) maxMemorySet); } catch (final NumberFormatException e) { ClientLogger.logQuietly(e); } } return max; } public static int getMaxMemoryFromSystemIniFileInMB(final Properties systemIni) { final String maxMemoryString = systemIni.getProperty(TRIPLEA_MEMORY_XMX, "").trim(); int maxMemorySet = -1; if (maxMemoryString.length() > 0) { try { maxMemorySet = Integer.parseInt(maxMemoryString); } catch (final NumberFormatException e) { ClientLogger.logQuietly(e); } } return maxMemorySet; } public static Properties setMaxMemoryInMB(final int maxMemoryInMB) { System.out.println("Setting max memory for TripleA to: " + maxMemoryInMB + "m"); final Properties prop = new Properties(); prop.put(TRIPLEA_MEMORY_USE_DEFAULT, "false"); prop.put(TRIPLEA_MEMORY_XMX, "" + maxMemoryInMB); return prop; } public static void clearMaxMemory() { final Properties prop = new Properties(); prop.put(TRIPLEA_MEMORY_USE_DEFAULT, "true"); prop.put(TRIPLEA_MEMORY_ONLINE_ONLY, "true"); prop.put(TRIPLEA_MEMORY_XMX, ""); GameRunner.writeSystemIni(prop); } public static void setUseMaxMemorySettingOnlyForOnlineJoinOrHost(final boolean useForOnlineOnly, final Properties prop) { prop.put(TRIPLEA_MEMORY_ONLINE_ONLY, "" + useForOnlineOnly); } public static boolean getUseMaxMemorySettingOnlyForOnlineJoinOrHost(final Properties systemIni) { final String forOnlineOnlyString = systemIni.getProperty(TRIPLEA_MEMORY_ONLINE_ONLY, "true"); return Boolean.parseBoolean(forOnlineOnlyString); } }