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

Level object memory leak on world unload #24

Closed
dktapps opened this issue Oct 14, 2016 · 5 comments
Closed

Level object memory leak on world unload #24

dktapps opened this issue Oct 14, 2016 · 5 comments
Assignees
Labels
Category: Core Related to internal functionality Resolution: Fixed

Comments

@dktapps
Copy link
Member

dktapps commented Oct 14, 2016

Issue description

When a world is unloaded, the Level object is not destroyed due to Position objects holding references to it. This causes myriad bugs, the most famous ones being examples like getName() on null (PocketMine/PocketMine-MP#4205), Level::getProvider returning null (iTXTech/Genisys#1908).

The memory leak is very minor, barely worthy of the name "leak" at all. However, the effects are widespread.

Why this happens

Players with spawn points in worlds that are later unloaded will, for example, hold Position objects pointing to their spawn point in the unloaded world. These Position objects hold strong references to the Level object, which is subsequently not destroyed even after everything related to it is closed, most notably the LevelProvider.

The getName() on null bug occurs when a player with a spawn point in an unloaded world either attempts to teleport back to their spawn point, or when they quit from the server and their data is saved.

Steps to reproduce the issue

  1. Set a player's spawn point in world x
  2. Unload world x
  3. Kill the player, or otherwise attempt to teleport them to their spawn point.

Possible solutions

Use Level ID

Instead of holding a direct Level reference, Position objects could instead keep the level ID of the level that it points to. Then, when getLevel() is called on a Position object, obtain a Level reference from the server directly. If the world is an unloaded world, this will return null.

Problems

  • Every Position object would either need to hold a Server reference, or obtain one on-demand using Server::getInstance().
  • Position currently has a public Level property. This is used directly by many things in the core, and removal of this property would require either a magic __get() method or all access to the level property to be done with Position::getLevel(), which would have to get a Level reference from the Server ondemand. Both of these solutions have potential to impact on performance due to how widespread the use of Position is.

Use WeakRef

Use WeakRef to hold a Level weak reference instead of a strong one. This would eliminate the problem, but would bring back some performance issues which are the reason Position weak references were removed before now (they previously did use weak references).

Problems

  • WeakRef doesn't play nice on PHP7, especially when used with pthreads.
  • Performance/memory impacts.

OS and versions

  • PocketMine-MP: 2fba107
  • PHP: doesn't matter
  • OS: doesn't matter
@dktapps dktapps added Status: Reproduced Bug has been reproduced, but cause has not yet been identified Category: Core Related to internal functionality labels Oct 14, 2016
@legoboy0215
Copy link
Contributor

You finally found the reason 👍

I think the first solution is more viable.

@dktapps
Copy link
Member Author

dktapps commented Oct 14, 2016

@legoboy0215 I've known for a while what the cause was, but spent a while trying to work out ways to fix it. I couldn't come up with a good way to do it, so I opened this.

@archie426
Copy link

I have noticed this on my server as well

@SOF3
Copy link
Member

SOF3 commented Oct 14, 2016

If you have to choose between the two solutions, use the former one. The impact of having a WeakRef in every position is really expensive.

I would like to enquire, however, if there is actually a big problem with the use of Server::getInstance()? Really, it isn't even laggy.

@dktapps dktapps added Status: Debugged Cause of the bug has been found, but not fixed and removed Status: Reproduced Bug has been reproduced, but cause has not yet been identified labels Oct 16, 2016
@dktapps dktapps self-assigned this Oct 30, 2016
@dktapps
Copy link
Member Author

dktapps commented Oct 30, 2016

Anyone fancy testing 87ba326 ?

@dktapps dktapps closed this as completed in e3c900e Nov 9, 2016
@dktapps dktapps added Resolution: Fixed and removed Status: Debugged Cause of the bug has been found, but not fixed labels Nov 9, 2016
dktapps added a commit to iTXTech/Genisys that referenced this issue Nov 9, 2016
This was referenced Jul 13, 2019
@supercrafter333 supercrafter333 mentioned this issue Jun 7, 2020
@Lycol50 Lycol50 mentioned this issue Jun 8, 2020
@ghost ghost mentioned this issue Jul 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Core Related to internal functionality Resolution: Fixed
Projects
None yet
Development

No branches or pull requests

4 participants