Skip to content

Commit 23a8b9f

Browse files
committed
Attempt to set a 'soft minimum' of 4GB during decompile.
1 parent f357cfa commit 23a8b9f

2 files changed

Lines changed: 33 additions & 12 deletions

File tree

src/main/java/net/minecraftforge/mcmaven/impl/Mavenizer.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public static void setDecompileMemory(String value) {
104104
// https://github.com/openjdk/jdk/blob/08c8520b39083ec6354dc5df2f18c1f4c3588053/src/hotspot/share/runtime/arguments.cpp#L3628
105105
private static final String[] DEFAULT_ARG_ENV = { "JAVA_OPTIONS", "_JAVA_OPTIONS", "JAVA_TOOL_OPIONS"};
106106
private static final String[] MEMORY_FLAGS = {"-Xmx", "-XX:MaxHeapSize", "-Xms"};
107-
private static void warnAboutMemory() {
107+
private static boolean warnAboutMemory() {
108108
var found = false;
109109
for (var env : DEFAULT_ARG_ENV) {
110110
var value = System.getenv(env);
@@ -119,9 +119,10 @@ private static void warnAboutMemory() {
119119
}
120120
if (found)
121121
LOGGER.warn("Please remove it if you run into memory related issues");
122+
return found;
122123
}
123124

124-
public static List<String> fillDecompileJvmArgs(List<String> args, boolean firstRun) {
125+
public static List<String> fillDecompileJvmArgs(List<String> args, boolean firstRun, boolean useDefaultGuess) {
125126
if (!firstRun)
126127
return args; // Use the unmodifed args from MCPConfig
127128

@@ -135,8 +136,14 @@ public static List<String> fillDecompileJvmArgs(List<String> args, boolean first
135136
// https://docs.oracle.com/en/java/javase/21/gctuning/ergonomics.html
136137
// There are old JVMs that limit it to 1GB but there is no good way to detect if we're using one so just hope.
137138
// https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/ergonomics.html
138-
// Best we can do is warn about memory argumetns if we see them.
139+
// Best we can do is warn about memory arguments if we see them.
139140
warnAboutMemory();
141+
142+
// Lets try and pick a 'sensible' default minimum size, this number is arbitrary, and causes issues with systems with low amounts of ram
143+
// I really hate just setting an arbitrary lower limit
144+
// If someone has a better idea how to deal with this feel free to submit it.
145+
if (useDefaultGuess)
146+
ret.add("-Xms4G");
140147
}
141148
return ret;
142149
}

src/main/java/net/minecraftforge/mcmaven/impl/repo/mcpconfig/MCPTaskFactory.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -834,19 +834,27 @@ private File execute(String name, List<TaskOrArg> jvmArgs, List<TaskOrArg> runAr
834834

835835
ToIntFunction<String> logHandler = null;
836836
if (isDecompile) {
837-
jvm = Mavenizer.fillDecompileJvmArgs(jvm, true);
837+
jvm = Mavenizer.fillDecompileJvmArgs(jvm, true, true);
838838
logHandler = MCPTaskFactory::parseDecompileLog;
839839
}
840840

841841
var ret = ProcessUtils.runJar(jdk, log.getParentFile(), log, tool, jvm, run, logHandler);
842-
if (ret.exitCode == OUT_OF_MEMORY && isDecompile) {
843-
var newJvm = Mavenizer.fillDecompileJvmArgs(resolveArgs(cache, tasks, jvmArgs), false);
844-
if (!newJvm.equals(jvm)) {
845-
LOGGER.error("First decompile failed with OutOfMemory using JVM Args: " + jvm);
846-
LOGGER.error("Attempting again with: " + newJvm);
847-
ret = ProcessUtils.runJar(jdk, log.getParentFile(), log, tool, newJvm, run, logHandler);
848-
if (ret.exitCode == OUT_OF_MEMORY)
849-
LOGGER.error("Ran out of memory again, you can specify more manually using the --decompile-memory Mavenizer argument");
842+
if (isDecompile) {
843+
if (ret.exitCode == NOT_ENOUGH_MEMORY) {
844+
LOGGER.error("Failed to create JVM with Not Enough Memory issue, Modern minecraft requires atleast 4GB to decompile. Run it on a system with more ram.");
845+
} else if (ret.exitCode == INVALID_INITAL_HEAP) {
846+
LOGGER.error("Attempted to run decompile with JVM args: " + jvm + " resulted in Invalid Inital and Max heap settings.");
847+
LOGGER.error("This is typically caused by you having a environement variable setting the global memory options, remove or set those variables to values higher then 4GB.");
848+
}
849+
if (ret.exitCode == OUT_OF_MEMORY || ret.exitCode == INVALID_INITAL_HEAP) {
850+
var newJvm = Mavenizer.fillDecompileJvmArgs(resolveArgs(cache, tasks, jvmArgs), false, false);
851+
if (!newJvm.equals(jvm)) {
852+
LOGGER.error("First decompile failed with OutOfMemory using JVM Args: " + jvm);
853+
LOGGER.error("Attempting again with: " + newJvm);
854+
ret = ProcessUtils.runJar(jdk, log.getParentFile(), log, tool, newJvm, run, logHandler);
855+
if (ret.exitCode == OUT_OF_MEMORY)
856+
LOGGER.error("Ran out of memory again, you can specify more manually using the --decompile-memory Mavenizer argument");
857+
}
850858
}
851859
}
852860
if (ret.exitCode != 0)
@@ -904,10 +912,16 @@ private List<String> resolveArgs(HashStore cache, Map<Task, String> tasks, List<
904912

905913
private static final int OUT_OF_MEMORY = -1001;
906914
private static final int FAILED_DECOMPILE = -1002;
915+
private static final int INVALID_INITAL_HEAP = -1003;
916+
private static final int NOT_ENOUGH_MEMORY = -1004;
907917
// Yes this is slow as fuck, but this is only run during a decompile run which is already slow,
908918
// This is to check if Fernflower is broken and returning success when it really failed.
909919
// It also eagerly exits the process when something fails so as to not waste time.
910920
private static int parseDecompileLog(String line) {
921+
if (line.startsWith("Initial heap size set to a larger value than the maximum heap size"))
922+
return INVALID_INITAL_HEAP;
923+
if (line.startsWith("Could not reserve enough space for object heap"))
924+
return NOT_ENOUGH_MEMORY;
911925
if (line.startsWith("java.lang.OutOfMemoryError:"))
912926
return OUT_OF_MEMORY;
913927
if (line.startsWith("Exception in thread") && line.contains("java.lang.OutOfMemoryError"))

0 commit comments

Comments
 (0)