Anuken / Mindustry

The automation tower defense RTS
https://mindustrygame.github.io
GNU General Public License v3.0
22.69k stars 2.97k forks source link

Memory usage boost on startup and opening the database #10063

Closed 91khr closed 3 months ago

91khr commented 3 months ago

Platforms

Linux

Build

146

Issue

During normal gameplay, the game typically uses <2G RAM on my machine. But on startup and the first time since start opening the database, the memory usage would boost to 4G~5G. This is more severe on a machine with low RAM (e.g. 8G), and sometimes can trigger the OOM killer.

I've inspected the function calls during the start process on a third-party client, and found that the biggest memory usage increment is after the execution of mindustry.ui.dialogs.KeybindDialog(), which has a 1.5G diff on my machine.

The code I used to inspect the memory usage ```diff diff --git a/build.gradle b/build.gradle index 6014be2..11ca1d5 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ buildscript{ plugins{ id "org.jetbrains.kotlin.jvm" version "1.9.20" id "org.jetbrains.kotlin.kapt" version "1.9.20" + id "io.freefair.aspectj" version "8.6" } allprojects{ @@ -106,6 +107,7 @@ project(":core"){ apply plugin: "java-library" apply plugin: "kotlin" apply plugin: "kotlin-kapt" + apply plugin: "io.freefair.aspectj" kapt{ javacOptions{ @@ -146,6 +148,7 @@ project(":core"){ } dependencies{ + api "org.aspectj:aspectjrt:1.9.22.1" api "org.lz4:lz4-java:1.8.0" api arcModule("arc-core") api arcModule("extensions:flabel") @@ -180,6 +183,19 @@ project(":core"){ }) destinationDir = new File(buildDir, 'javadoc') } + + compileAspectj { + dependsOn compileJava + dependsOn compileKotlin + def depfiles = files(project.configurations.compileClasspath) + files(compileJava.outputs) + + files(compileKotlin.outputs) + //depfiles.each { println it } + ajcOptions { + sourceroots.from files(kaptKotlin.outputs) + classpath.from depfiles + compilerArgs += ['-showWeaveInfo', '-progress', '-log', '/dev/stdout'] + } + } } //comp** classes are only used for code generation diff --git a/core/src/main/advice/Advice.java b/core/src/main/advice/Advice.java new file mode 100644 index 0000000..ec0b7f1 --- /dev/null +++ b/core/src/main/advice/Advice.java @@ -0,0 +1,71 @@ +package main.advice; + +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import arc.util.Log; + +@Aspect +public class Advice { + static int indent = 0; + static long prevmem = 0; + + static long analMem(Path memfile) throws IOException { + List lns = Files.readAllLines(memfile); + long mem = Long.parseLong(lns.get(0)); + return mem; + } + static String fmtmem(long mem) { + boolean negi = mem < 0; + if (mem < 0) + mem = -mem; + String[] units = new String[]{ "b", "kB", "mB", "gB" }; + ArrayList show = new ArrayList<>(); + for (int i = 0; mem > 0; mem /= 1024, ++i) + show.add(MessageFormat.format("{0}{1}", mem % 1024, units[i])); + Collections.reverse(show); + if (show.isEmpty()) + show.add("0b"); + return (negi ? "-" : "") + String.join(" ", show); + } + public static void printMemUsage() { + try { + String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; + List lns = Files.readAllLines(Paths.get(MessageFormat.format("/proc/{0}/cgroup", pid))); + String group = Paths.get("/sys/fs/cgroup", lns.get(0).split(":")[2]).toString(); + long curmem = analMem(Paths.get(group, "memory.current")); + Log.debug("@Memory: current @, peak @, diff @", " ".repeat(indent), fmtmem(curmem), + fmtmem(analMem(Paths.get(group, "memory.peak"))), fmtmem(curmem - prevmem)); + prevmem = curmem; + } catch (Exception e) { + Log.err(e); + } + } + + /* + static final String cond = "execution(mindustry.ui.fragments.*.new(..)) || execution(* mindustry.ui.fragments.*.build(..)) ||" + + "execution(mindustry.ui.dialogs.*.new(..)) || execution(* mindustry.ui.dialogs.*.build(..)) ||" + + "execution(mindustry.editor.MapEditorDialog.new(..)) || execution(* mindustry.editor.MapEditorDialog.build(..)) ||" + + "execution(* mindustry.ui.fragments.*.build(..)) || execution(* arc.ApplicationListener.init(..))"; + */ + static final String cond = "execution(* mindustry.*.*(..))"; + @Before(cond) + public void beforeBuild(JoinPoint point) { + Log.debug("@Before: @ do @", " ".repeat(indent), point.getSourceLocation().toString(), point); + printMemUsage(); + ++indent; + } + + @After(cond) + public void afterBuild() { + --indent; + } +} \ No newline at end of file ```

Steps to reproduce

Just start the game and open the database. The memory usage would decrease gradually after entering the menu, and would boost again when opening the database.

Mods used

No response

Save file

No response

(Crash) logs

No response

Submission

Anuken commented 3 months ago

Cannot reproduce the issue. The memory usage remains more or less constant upon opening those dialogs, and it makes no sense for it to consume so much RAM. Are you certain you're not using mods?

image

91khr commented 3 months ago

I'm sure, since I've not installed any mods.

The main process itself may not consume much memory, but there would be a significant memory usage boost in system memory usage. It would be clearer if it's started in its own cgroup:

systemd-run --user mindustry
systemctl --user status run-xxxxx

And on my machine this was shown:

On Fri, Jul 26, 2024 at 07:28:33PM -0700, Anuken wrote:

Cannot reproduce the issue. The memory usage remains more or less constant upon opening those dialogs, and it makes no sense for it to consume so much RAM. Are you certain you're not using mods?

image

-- Reply to this email directly or view it on GitHub: https://github.com/Anuken/Mindustry/issues/10063#issuecomment-2253715085 You are receiving this because you authored the thread.

Message ID: @.***>

Anuken commented 3 months ago

The main process itself may not consume much memory, but there would be a significant memory usage boost in system memory usage.

Unless the System Monitor program is wildly inaccurate (which sounds implausible), there is no increase in any kind of memory when I open those dialogs.