|
|
|
Mythic Dungeons loads and unloads worlds on a regular basis in order to create private experiences for every party. This is a natively supported function of Bukkit (and consequently Spigot and its forks, such as Paper and Purpur.)
|
|
|
|
|
|
|
|
However, this is a system that is quite infrequently used. As such, there are a lot of plugins out there that don't properly work with it safely. This can cause major memory leaks, where Mythic Dungeons attempts to unload the world, but another plugin on the server keeps that world in memory.
|
|
|
|
|
|
|
|
## Troubleshooting Memory Leaks
|
|
|
|
Most memory leaks in recent versions of Mythic Dungeons are caused by other plugins. We have done everything we can to mitigate them, but some plugins still keep the dungeon worlds alive. It can be difficult to diagnose, but here's some guidance on how to investigate the cause.
|
|
|
|
|
|
|
|
_You will need to use Paper or a fork of Paper!_
|
|
|
|
|
|
|
|
If your server has been online for a while and has accumulated a lot of RAM usage, run the command `/paper heap` and it will create what we call a heap dump in your server's 'dumps' folder. Heap dumps contain tons of valuable information for developers about how different plugins and systems are communicating with each other. They are often several GB large though, so make sure you've got plenty of disk space!
|
|
|
|
|
|
|
|
From here you have two options:
|
|
|
|
1. Inspect the heap dump yourself using [Eclipse Memory Analyzer](https://eclipse.dev/mat/)
|
|
|
|
2. Upload the heap dump to a file hosting site and share it on [the issue tracker.](https://git.lumine.io/mythiccraft/MythicDungeons/-/issues)
|
|
|
|
|
|
|
|
### Inspecting Heap Dumps
|
|
|
|
Inspecting heap dumps is a VERY valuable skill to have, and is the recommended way to troubleshoot memory leaks caused by dungeon worlds! You'll need Eclipse Memory Analyzer (linked above). It's very easy to install and there are detailed instructions below on how to search for memory leaks.
|
|
|
|
|
|
|
|
_NOTE: You may need a large amount of memory on your computer to inspect particularly big heap dumps!_
|
|
|
|
|
|
|
|
First, you need to load up your heap dump. Open Eclipse Memory Analyzer, then from the top drop-down choose `file` and then `open heap dump`. Navigate to where you've saved it on your computer and open it.
|
|
|
|
|
|
|
|
![](https://i.imgur.com/AxRAme9.png)
|
|
|
|
|
|
|
|
It may take some time for your heap dump to finish loading, but once it does, just close the window the pops up. From here, you'll want to click the `Open Dominator tree` button indicated here.
|
|
|
|
|
|
|
|
![](https://i.imgur.com/xlC4J4h.png)
|
|
|
|
|
|
|
|
Once that's open, you'll see a massive list like a spreadsheet. At the top will be a section labeled `<Regex>`. Click on it and type in `net.minecraft.server.level.WorldServer` (or `net.minecraft.server.level.ServerLevel` for Minecraft 1.21+), then press enter. You should see a list of worlds now.
|
|
|
|
|
|
|
|
![](https://i.imgur.com/GMeep7W.png)
|
|
|
|
|
|
|
|
Right-click one of them and choose `Path to GC Roots > exclude weak references`. This will show you what is holding on to the world. The main thing you're looking for in the various drop-downs is other plugins. If you're having trouble identifying what the cause it, feel free to take a screenshot of the page and share it in the support channel on Discord.
|
|
|
|
|
|
|
|
If you identify a plugin as the cause of the memory leak, it's recommended to submit an issue to the developer of that plugin, as it's very unlikely Mythic Dungeons can do anything about it.
|
|
|
|
|
|
|
|
### Sharing with a developer
|
|
|
|
If you are having trouble inspecting the heap dump yourself, you _may_ share the heap dump on the issue tracker and a developer will attempt to inspect it when they have time.
|
|
|
|
|
|
|
|
## [DEVELOPERS] How to not create memory leaks with your plugin
|
|
|
|
There are a few tricks to avoiding accidentally creating memory leaks due to the dynamic worlds that Bukkit/Spigot allows. Here's a little overview of things to watch out for.
|
|
|
|
|
|
|
|
### Catch the "WorldUnloadEvent"!!
|
|
|
|
If you're tracking world data, stop tracking it when the world is unloaded! This is a VERY easy and simple way to make sure you don't keep holding on to worlds that no longer exists, and can be done just with a standard event handler provided by the Spigot API.
|
|
|
|
|
|
|
|
### Avoid hard-referencing the `World` object!
|
|
|
|
If you reference a world object anywhere, that will keep it in memory. For example, if you have an object with a World field such as:
|
|
|
|
`private World world;`
|
|
|
|
The world will remain in memory until you set `world` to null.
|
|
|
|
|
|
|
|
A great way to combat this is to use something called a WeakReference. A weak reference will allow the world to still be unloaded from memory. Here's how to use it:
|
|
|
|
```java
|
|
|
|
public class MyClass {
|
|
|
|
// Here's our weak reference.
|
|
|
|
private WeakReference<World> worldRef;
|
|
|
|
|
|
|
|
public MyClass(World world) {
|
|
|
|
worldRef = new WeakReference<>(world); // You create a WeakReference with `new` and pass the world as the constructor argument.
|
|
|
|
}
|
|
|
|
|
|
|
|
public World getWorld() {
|
|
|
|
return worldRef.get(); // The `.get()` call returns the world stored at the weak reference. If the world is unloaded, it'll return null.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Avoid hard-referencing entities!
|
|
|
|
Entities contain a hard reference to the World object! This will ALSO keep worlds alive in memory, so if you need to hold on to an entity, use a `WeakReference<Entity>`. (A WeakHashMap is also a good choice if you need a map, as it will allow the key to be unloaded.) |
|
|
|
\ No newline at end of file |