diff --git a/vassal-app/src/main/java/VASSAL/build/module/GlobalOptions.java b/vassal-app/src/main/java/VASSAL/build/module/GlobalOptions.java index 413d105d82..7d79907d94 100644 --- a/vassal-app/src/main/java/VASSAL/build/module/GlobalOptions.java +++ b/vassal-app/src/main/java/VASSAL/build/module/GlobalOptions.java @@ -98,6 +98,7 @@ public class GlobalOptions extends AbstractConfigurable implements ComponentDesc public static final String STORE_LEADING_ZERO_INTEGERS_AS_STRINGS = "storeLeadingZeroIntegersAsStrings"; //NON-NLS public static final String PURGE_BLANK_PROPERTY_PROMPTS = "purgeBlankPropertyPrompts"; //NON-NLS public static final String DISABLE_PIECE_INDEXING = "disablePieceIndexing"; + public static final String MIN_MAXIMUM_HEAP = "minMaxHeap"; // Hybrid preference settings public static final String ALWAYS = "Always"; //$NON-NLS-1$ @@ -153,6 +154,7 @@ public class GlobalOptions extends AbstractConfigurable implements ComponentDesc private boolean storeLeadingZeroIntegersAsStrings = false; // Store integers with leading zeroes as String internally private boolean purgeBlankPropertyPrompts = true; // Purge blank property prompts private boolean disableUsePieceIndexes = false; // Should FastMatch use piece Indexes? + private int minMaxHeap = 0; // Module designer's specified minimum for the Max Heap preference // Configurable prompt string for unmask-my-pieces private String promptString = Resources.getString("GlobalOptions.opponents_can_unmask_my_pieces"); @@ -229,10 +231,17 @@ public void addTo(Buildable parent) { final IntConfigurer maxHeapConf = new IntConfigurer( MAXIMUM_HEAP, Resources.getString("GlobalOptions.maximum_heap"), //$NON-NLS-1$ - AbstractLaunchAction.DEFAULT_MAXIMUM_HEAP + Math.max(AbstractLaunchAction.DEFAULT_MAXIMUM_HEAP, minMaxHeap) ); prefs.addOption(maxHeapConf); + // Startup - Special handling for max heap - override general preference with a module default, if higher + if (minMaxHeap > (Integer.parseInt(((prefs.getValue(MAXIMUM_HEAP)).toString())))) { + prefs.setValue(MAXIMUM_HEAP, minMaxHeap); + gm.warn("~" + Resources.getString("GlobalOptions.module_minimum_heap", minMaxHeap)); + + } + //BR// Drag Threshold - # pixels mouse must move to distinguish drag from click final IntConfigurer dragThresholdConf = new IntConfigurer( DRAG_THRESHOLD, @@ -477,7 +486,8 @@ public String[] getAttributeDescriptions() { Resources.getString("Editor.GlobalOption.send_to_location_movement_trails"), Resources.getString("Editor.GlobalOption.leading_zero_integer_strings"), Resources.getString("Editor.GlobalOption.purge_blank_property_prompts"), - Resources.getString("Editor.GlobalOption.disable_use_location_indexes") + Resources.getString("Editor.GlobalOption.disable_use_location_indexes"), + Resources.getString("Editor.GlobalOption.min_maximum_heap") }; } @@ -499,7 +509,8 @@ public String[] getAttributeNames() { SEND_TO_LOCATION_MOVE_TRAILS, STORE_LEADING_ZERO_INTEGERS_AS_STRINGS, PURGE_BLANK_PROPERTY_PROMPTS, - DISABLE_PIECE_INDEXING + DISABLE_PIECE_INDEXING, + MIN_MAXIMUM_HEAP ) ); @@ -525,7 +536,8 @@ public Class[] getAttributeTypes() { PromptOnOff.class, Boolean.class, Boolean.class, - Boolean.class + Boolean.class, + Integer.class }; } @@ -662,6 +674,9 @@ else if (PURGE_BLANK_PROPERTY_PROMPTS.equals(key)) { else if (DISABLE_PIECE_INDEXING.equals(key)) { return String.valueOf(disableUsePieceIndexes); } + else if (MIN_MAXIMUM_HEAP.equals(key)) { + return Integer.toString(minMaxHeap); + } else if (INVENTORY_VISIBLE_TO_ALL.equals(key)) { return inventoryVisibleToAll; } @@ -764,6 +779,24 @@ else if (value instanceof String) { disableUsePieceIndexes = "true".equals(value); //NON-NLS } } + else if (MIN_MAXIMUM_HEAP.equals(key)) { + if (value instanceof String) { + Integer i; + try { + i = Integer.parseInt((String) value); + } + catch (NumberFormatException e) { + // invalid input leaves the setting unchanged but remains on the UI until a module restart + i = null; + } + if (i != null) { + minMaxHeap = i; + } + } + else if (value instanceof Integer) { + minMaxHeap = (int) value; + } + } else if (INVENTORY_VISIBLE_TO_ALL.equals(key)) { inventoryVisibleToAll = (String) value; } @@ -876,6 +909,11 @@ public boolean isDisableUsePieceIndexes() { return disableUsePieceIndexes; } + /** @return minimum Max Heap - will override user preference if that is set lower */ + public int getMinMaximumHeap() { + return minMaxHeap; + } + /** @return whether specific hybrid preference is enabled (could be designer-forced setting, could be player preference) */ private boolean isEnabled(String attValue, String prefsPrompt) { if (ALWAYS.equals(attValue)) { diff --git a/vassal-app/src/main/java/VASSAL/launch/AbstractLaunchAction.java b/vassal-app/src/main/java/VASSAL/launch/AbstractLaunchAction.java index 84d576ad8a..010b77fd2b 100644 --- a/vassal-app/src/main/java/VASSAL/launch/AbstractLaunchAction.java +++ b/vassal-app/src/main/java/VASSAL/launch/AbstractLaunchAction.java @@ -112,7 +112,7 @@ public AbstractLaunchAction(String name, Window window, } /** - * @return true iff any files are in use + * @return true if any files are in use */ public static boolean anyInUse() { return useTracker.anyInUse(); @@ -120,7 +120,7 @@ public static boolean anyInUse() { /** * @param file the file to check - * @return true iff the file is in use + * @return true if the file is in use */ public static boolean isInUse(File file) { return useTracker.isInUse(file); @@ -128,7 +128,7 @@ public static boolean isInUse(File file) { /** * @param file the file to check - * @return true iff the file is being edited + * @return true if the file is being edited */ public static boolean isEditing(File file) { return useTracker.isEditing(file); @@ -232,7 +232,7 @@ protected boolean checkRemovedAndDeprecated(File f) throws IOException { lr.mode == LaunchRequest.Mode.EDIT_EXT; final LocalDate sixMonthsFromNow = LocalDate.now().plusMonths(6); - // convert deprecation date to date elgible for removal (+1 year) + // convert deprecation date to date eligible for removal (+1 year) final DateTimeFormatter fmt = DateTimeFormatter.ISO_LOCAL_DATE; for (final Map.Entry> e1: deprecated.entrySet()) { for (final Map.Entry e2: e1.getValue().entrySet()) { @@ -381,6 +381,10 @@ public Void doInBackground() throws InterruptedException, maximumHeap = getHeapSize( p, GlobalOptions.MAXIMUM_HEAP, DEFAULT_MAXIMUM_HEAP ); + + // log the JVM maximum heap + logger.info("JVM maximum heap size: {} MB", maximumHeap); //NON-NLS + } } else if (lr.importFile != null) { diff --git a/vassal-app/src/main/resources/VASSAL/i18n/Editor.properties b/vassal-app/src/main/resources/VASSAL/i18n/Editor.properties index cb1b17dd2d..f7c1c38d9d 100644 --- a/vassal-app/src/main/resources/VASSAL/i18n/Editor.properties +++ b/vassal-app/src/main/resources/VASSAL/i18n/Editor.properties @@ -1129,6 +1129,8 @@ Editor.GlobalOption.send_to_location_movement_trails=Send-to-Location trait gene Editor.GlobalOption.leading_zero_integer_strings=Preserve leading zeros in Integers? Editor.GlobalOption.purge_blank_property_prompts=Purge blank lines from dynamic/global property prompts? Editor.GlobalOption.disable_use_location_indexes=Disable use of location indexes to speed up Global Key Commands? +Editor.GlobalOption.min_maximum_heap=Minimum JVM maximum heap (in MB) + # Global Properties Editor.GlobalProperties.component_type=Global Properties diff --git a/vassal-app/src/main/resources/VASSAL/i18n/VASSAL.properties b/vassal-app/src/main/resources/VASSAL/i18n/VASSAL.properties index 6f170f2a31..ad15d13638 100644 --- a/vassal-app/src/main/resources/VASSAL/i18n/VASSAL.properties +++ b/vassal-app/src/main/resources/VASSAL/i18n/VASSAL.properties @@ -797,6 +797,7 @@ GlobalOptions.center_on_move_sensitivity=Recenter Sensitivity (% of edge/center GlobalOptions.auto_report=Auto-report moves GlobalOptions.mark_moved=Mark moved pieces GlobalOptions.maximum_heap=JVM maximum heap (in MB) +GlobalOptions.module_minimum_heap=JVM maximum heap increased to module minimum (%1$s MB). Module restart required! GlobalOptions.bug10295=Override native drag-and-drop image (if image missing or too dim when dragging counters) GlobalOptions.classic_mfd=Use Classic Move Fixed Distance trait move batching GlobalOptions.mouse_drag_threshold=Mouse drag threshold diff --git a/vassal-doc/src/main/readme-referencemanual/ReferenceManual/GlobalOptions.adoc b/vassal-doc/src/main/readme-referencemanual/ReferenceManual/GlobalOptions.adoc index e63a4ba32a..25a5c2268e 100644 --- a/vassal-doc/src/main/readme-referencemanual/ReferenceManual/GlobalOptions.adoc +++ b/vassal-doc/src/main/readme-referencemanual/ReferenceManual/GlobalOptions.adoc @@ -44,6 +44,9 @@ NOTE: If you later need to do arithimetic on this value in a Beanshell expressio [#disableindex] *Disable use of location indexes to speed up Global Key Command?*:: A new feature was added to Vassal 3.7 to speed up the execution of all varieties of Global Key Commands (GKCs) where a <> 'by location' has been specified. It also speeds up all Ranged GKCs. The use of these indexes can cause the GKCs to be applied to matching pieces in a different order than previously. Modules should not make any assumptions about the order that GKCs are applied to matching pieces. This option turns off the use of location indexes to speed up GKCs and reverts to the slower pre 3.7 behaviour. +[#minimumheap] +*Minimum JVM maximum heap (in MB):*:: The module designer can specify a minimum setting for the user preference <> here. When the module starts up, the JVM setting is checked against this value. If the Global Options value is higher, the user preference will be overwritten and a warning message will advise that a restart is required. + *Icons and hotkeys:*:: You can specify your own button icons and keyboard shortcuts for the logfile step/undo buttons, the button that shows/hides the server controls, a button to display the Debug Window and a button to show the <> windows if you have defined any. |image:images/GlobalOptions.png[] diff --git a/vassal-doc/src/main/readme-referencemanual/ReferenceManual/Preferences.adoc b/vassal-doc/src/main/readme-referencemanual/ReferenceManual/Preferences.adoc index a7c2abdc85..2d84679a70 100644 --- a/vassal-doc/src/main/readme-referencemanual/ReferenceManual/Preferences.adoc +++ b/vassal-doc/src/main/readme-referencemanual/ReferenceManual/Preferences.adoc @@ -55,9 +55,10 @@ NOTE: This option is intended for debugging only and can degrade the performance *Use combined application window (requires restart):*:: Check this option to have the first Map#top,Map>> in each module open as part of the same window that includes the ChatLog#top,Chat Log>> and main module menu. If unchecked, all Maps will have their own windows. -*JVM maximum heap (in MB):*:: This sets the maximum size (in megabytes) of the heap that Java uses to manage memory for the VASSAL applications. The two times you should consider increasing this value are: (1) if you receive an Out of Memory exception, and (2) you notice that map tiles are taking a really long time to paint. If either of these two things happens, try bumping it up by increments of 256 -- it is uncommon enough to need to adjust it at all, and, e.g., 768 is often fine. 1024 handles even most very large modules, and we've rarely encountered a module in 20 years that needed more than 2048. Note that increasing this number in situations where it is not needed will end up disincentivizing Java from managing memory as tightly -- so don't increase this to massive numbers "just because you can". +[#JVMmaxheap] +*JVM maximum heap (in MB):*:: This sets the maximum size (in megabytes) of the heap that Java uses to manage memory for the VASSAL applications. The two times you should consider increasing this value are: (1) if you receive an Out of Memory exception, and (2) you notice that map tiles are taking a really long time to paint. If either of these two things happens, try bumping it up by increments of 256 -- it is uncommon enough to need to adjust it at all, and, e.g., 768 is often fine. 1024 handles even most very large modules, and we've rarely encountered a module in 20 years that needed more than 2048. Note that increasing this number in situations where it is not needed will end up disincentivizing Java from managing memory as tightly -- so don't increase this to massive numbers "just because you can". The module may overwrite this setting with a higher value and will log a warning if it does so. -NOTE: changing this value will have no effect until the next time you start the module in the VASSAL Player or Editor. +NOTE: changing this value will have no effect until the next time you start the module in the VASSAL Player or Editor. This applies even if the module itself overwrites the setting. *Mouse Drag Threshold:*:: When VASSAL is distinguishing a mouse "click" from a mouse "drag", this is the minimum distance in pixels that the mouse must be moved (with a button pressed) in order to be considered a "drag". Smaller values will allow more sensitive drag detection, but can result in "clicks" being misinterpreted as drags. Larger numbers mean a piece will have to be dragged further before it begins "dragging". diff --git a/vassal-doc/src/main/readme-referencemanual/ReferenceManual/images/GlobalOptions.png b/vassal-doc/src/main/readme-referencemanual/ReferenceManual/images/GlobalOptions.png index 6d2cbe9043..00a26d44d7 100644 Binary files a/vassal-doc/src/main/readme-referencemanual/ReferenceManual/images/GlobalOptions.png and b/vassal-doc/src/main/readme-referencemanual/ReferenceManual/images/GlobalOptions.png differ