XboxChaos / Assembly

Multi-Generation Blam Engine Research Tool
http://www.xboxchaos.com/
GNU General Public License v3.0
224 stars 94 forks source link

Improve Garbage Collection #268

Open executionByFork opened 4 years ago

executionByFork commented 4 years ago

Assembly's Blamite seems to suffer from poor garbage collection which leads to runaway memory leakage. This can primarily be seen when applying patches, and also when loading maps.

When starting Assembly, before loading in anything, it uses a measly 60 MB image

Upon opening a .asmp patch file, the memory jumps up because it loads a bunch of data from the file. In this example, I am using Krevil's LNOS Corvette mod, which causes about a 500MB jump in Assembly. image

The above makes sense up until I apply the patch and close the tab in Assembly. After doing this, the memory raises further by about 40MB then drops very slightly once the patch is applied. However, overall there is a net gain in memory usage when patching. image

Because I have applied the patch and closed the only open tab in Assembly, there should be a large drop in memory usage. The fact that there is not is indication of a major memory leak. Furthermore, this issue compounds. Leaving Assembly open, I restore the original map file I modified with the patch. Then I open up the same patch as before, apply it to the same map file, then close the tab again. This leads to Assembly hogging an entire gigabyte of memory. image

This same behavior occurs on a smaller scale when opening and closing the same map file to view the tags. Though the memory increases are comparatively smaller each iteration, they all still stack on top of one another.

I came across this issue when using the Blamite DLL methods in my mod manager to add support for using assembly patch files. I can say for certain that this memory leakage is present in the Blamite project, though there are probably other places in Assembly that cause this same problem. I believe the cause might be the use of class wide variables which are never properly disposed of. They are used as globals in a sense, so that the data does not have to be passed into methods/classes. However I can't say I am extremely familiar with Assembly internals as I haven't spent much time inside the code.

Whatever is happening, this issue should be addressed as it can cause a computer to slow down considerably on machines with low RAM when doing heavy editing in Assembly across multiple files, especially when testing patches.

adierking commented 4 years ago

Thanks for reporting!

Looks like there are two separate issues here:

  1. The patching code wasn't intended to handle large patches and it works by loading the entire patch file into memory. This probably isn't necessary to do, but it worked back in the Xbox 360 era because most patches were very small (usually a few megabytes at most). We'd need to rewrite the patching code to solve this for large files.

  2. It seems like the patch isn't being garbage-collected when the tab is closed. This is definitely a problem. A heap snapshot is showing that this might be related to AutomationPeers:

Screenshot