Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force GC on auto-pause to save RAM #2687

Open
walking-octopus opened this issue Mar 1, 2024 · 4 comments
Open

Force GC on auto-pause to save RAM #2687

walking-octopus opened this issue Mar 1, 2024 · 4 comments

Comments

@walking-octopus
Copy link

walking-octopus commented Mar 1, 2024

Problem

Auto-pause, despite saving the CPU power, does little to curb the rather enormous RAM usage a Minecraft server, especially with Forge, can impose on the system, being rather problematic for installations where Minecraft lives alongside other services like a home server. Auto-shutdown may seem like a solution, but as far as I can see, it doesn't support automatic startup on new network connections like auto-pause, so isn't considered a viable alternative.

Proposed solution

I propose to amend this feature by forcing the JVM to perform a garbage collection before pausing. One way I found of achieving it would look something like

jcmd $(jps -l | grep forge-1.12.2-14.23.5.2860.jar | awk '{print $1}') GC.run

which would require the following options for the JVM to enable debugging

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Perhaps there is a better implementation, but this serves as illustration for my proposal. This simple feature may make a great difference for many RAM-scarce homelabs.

Alternatives considered

@walking-octopus walking-octopus changed the title Force garbage collection on auto-pause to save RAM Force GC on auto-pause to save RAM Mar 1, 2024
@itzg
Copy link
Owner

itzg commented Mar 1, 2024

Thanks, that is a good suggestion.

My concern is that garbage collection will compact the JVM's heap memory, but I don't believe it will release any of that heap allocation back to the operating system. Can you research that with one of your running instances?

I'm also pretty sure that jcmd is not included with the JRE base images, just the JDK (includes full development kit, compiler, etc).

@walking-octopus
Copy link
Author

walking-octopus commented Mar 1, 2024

You're right, it seems JVM really doesn't like releasing memory back to the OS. However I found a few flags that may help. I'm not a Java developer, so perhaps there is some performance cost or nuance I wasn't aware of.

  • -XX:-ShrinkHeapInSteps in JDK 9 will force the JVM to more aggressively release memory at a performance cost.
  • -XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30 can instruct JVM 8 to release memory under a certain idle/low load state.
  • JDK 12 seems to by default release unused memory as seen here.

I haven't yet had the opportunity to test any of this but perhaps this can force the JVM to not hold onto memory when paused.

Also, how is the pause feature implemented? Is the process itself paused or is the JVM aware of it? If any of this is enabled, could JVM regard this as idle state and release the unused memory?

I'm anything but an expert here, so please correct me if I am wrong.

@itzg
Copy link
Owner

itzg commented Mar 2, 2024

Good research. So it might turn out that users adding those options for Java 8 containers and relying on the default G1 for Java 17 etc might the best that can be done anyway.

To answer your question it pauses the process as a whole with a STOP signal

So I don't believe the JVM will be aware of that or even given a chance to interpret it.

@walking-octopus
Copy link
Author

walking-octopus commented Mar 2, 2024

  1. I suppose the server already has plenty of time of inactivity, so with these options the GC might just run and compact/free some of the heap itself. The only possible change could be at best making them a default if adding them does change anything about the memory footprint...

  2. The kernel understands quite well that these hung processes make for prime swapping candidates. If there's any deficit of RAM, it would already start swapping them as is. But for the purposes of housekeeping, wouldn't it be nice to trigger this sooner than later since we've assumed the server would be off for some time before pausing it? I found one approach to doing so here.

There is a special syscall process_madvise you can use that that lets you select mappings of memory from a foreign process and you can pass the MADVISE_PAGEOUT flat to fault out the memory into swap.

I wonder if it can be called inside the container to instantly swap most of the server's memory usage.

Sadly though, after testing it, it doesn't seem it swaps out more than ~25% of the memory...

  1. Maybe it would be better to support knock for server startup? Instead of stopping the container, we can keep the auto-start process running...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants