KSP memory leaks
gotmachine opened this issue · 0 comments
KSP is leaking managed memory from various places, but mainly due to GameEvents delegates that are never removed.
Worst offender by far is the PartSet
class which is holding Part
references, is instantiated (massively) and owned by a bunch of classes (ShipConstruct
, Vessel
, Part
...) and is subscribing to 2 GameEvents
. It attempts to unsubscribe from those GameEvents
with a GC finalizer, which obviously doesn't work since the GameEvents
subscriptions are preventing those objects from being collected in the first place.
There are many other offenders, with the end result being that all Vessel
or Part
ever instantiated will actually never be collected. Since those are rather top level objects themself holding a rather large reference tree, the end result is an ever ballooning heap allocated memory. On average, for a stock game (figures will likely be much higher with mods), every part ever instantiated will cause a permanent leak of ~0.2MB.
As shown in the following table, quick-loading the same flight scene with a ~150 parts vessel causes a leak of about ~30 MB per scene switch. After 17 scene switches, about 450 MB of memory is forever lost.
Scene load # | GameEvents callbacks (Stock) | GameEvents callbacks (KSPCF) | Allocated heap (MB) (Stock) | Allocated heap (MB) (KSPCF) | Leaks (MB) (Stock) | Leaks (MB) (KSPCF) |
---|---|---|---|---|---|---|
1 | 3142 | 1020 | 742,0 | 783,5 | ||
2 | 5268 | 1024 | 805,1 | 856,4 | ||
3 | 7394 | 1046 | 834,2 | 878,8 | 29,1 | 22,3 |
4 | 9520 | 1032 | 850,5 | 882,9 | 16,3 | 4,1 |
5 | 11646 | 1036 | 877,8 | 874,6 | 27,3 | -8,2 |
6 | 13772 | 1040 | 906,5 | 852,6 | 28,7 | -22,1 |
7 | 15898 | 1044 | 933,7 | 858,9 | 27,2 | 6,3 |
8 | 18024 | 1048 | 966,9 | 849,7 | 33,2 | -9,2 |
9 | 20150 | 1052 | 1012,4 | 880,8 | 45,6 | 31,2 |
10 | 22276 | 1056 | 1090,6 | 850,4 | 78,1 | -30,4 |
11 | 24402 | 1060 | 1121,3 | 810,7 | 30,7 | -39,8 |
12 | 26528 | 1064 | 1150,0 | 827,2 | 28,7 | 16,6 |
13 | 28654 | 1068 | 1179,6 | 849,1 | 29,7 | 21,8 |
14 | 30780 | 1072 | 1212,4 | 891,1 | 32,8 | 42,1 |
15 | 32906 | 1076 | 1239,0 | 850,4 | 26,6 | -40,7 |
16 | 35032 | 1080 | 1270,8 | 849,4 | 31,7 | -1,0 |
17 | 37158 | 1084 | 1301,5 | 850,0 | 30,7 | 0,6 |
Note that aside from increasing memory usage, this also cause performance degradation :
- Heap will become more fragmented and GC collections will take longer.
- "Dead" GameEvents delegate are still called, slowing down event processing and potentially causing weird side issues.
The KSPCF MemoryLeaks patch add a callback when a scene is exited, and walks through all GameEvents
delegates to remove entries whose owner is a destroyed UnityEngine.Object
derivative. There are just to many cases of leaked GameEvents
, so instead of trying to fix every one of them, this is a cheap way to work around the whole issue. Moreover, this will also cover leaks coming from plugins (which I suspect are even worse offenders than stock).
A specific handling is added for the PartSet
GameEvents leaks, since the class doesn't derive from UnityEngine.Object
.
The patch also implement various concrete fixes for a bunch of non-GameEvents related leaks, mainly caused by static fields misuse and lazyness.