diff --git a/jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java b/jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java index 260333ab8..680d1c2f9 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java @@ -1,6 +1,7 @@ package jadx.gui.ui; import jadx.gui.utils.NLS; +import jadx.gui.utils.Utils; import javax.swing.*; import java.awt.*; @@ -44,7 +45,7 @@ public class HeapUsageBar extends JProgressBar implements ActionListener { setValue(usedKB); setString(String.format(textFormat, (usedKB / TWO_TO_20), maxGB)); - if (used > r.maxMemory() * 0.8) { + if ((used + Utils.MIN_FREE_MEMORY) > r.maxMemory()) { setForeground(RED); } else { setForeground(GREEN); diff --git a/jadx-gui/src/main/java/jadx/gui/utils/Utils.java b/jadx-gui/src/main/java/jadx/gui/utils/Utils.java index 1a90f8999..c709350dd 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/Utils.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/Utils.java @@ -26,6 +26,16 @@ public class Utils { public static final Font FONT_HACK = openFontTTF("Hack-Regular"); + /** + * The minimum about of memory in bytes we are trying to keep free, otherwise the application may run out of heap + * which ends up in a Java garbage collector running "amok" (CPU utilization 100% for each core and the UI is + * not responsive). + * + * We can calculate and store this value here as the maximum heap is fixed for each JVM instance + * and can't be changed at runtime. + */ + public static final long MIN_FREE_MEMORY = calculateMinFreeMemory(); + private Utils() { } @@ -107,11 +117,21 @@ public class Utils { return overIcon; } + /** + * @return 20% of the maximum heap size limited to 512 MB (bytes) + */ + public static long calculateMinFreeMemory() { + Runtime runtime = Runtime.getRuntime(); + long minFree = (long) (runtime.maxMemory() * 0.2); + minFree = Math.min(minFree, 512 * 1048576); + return minFree; + } + public static boolean isFreeMemoryAvailable() { Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); - long totalFree = runtime.freeMemory() + maxMemory - runtime.totalMemory(); - return totalFree > maxMemory * 0.2; + long totalFree = runtime.freeMemory() + (maxMemory - runtime.totalMemory()); + return totalFree > MIN_FREE_MEMORY; } public static String memoryInfo() {