mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-06 21:26:07 +00:00
LzmaStream does not free memory #335
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @claunia on GitHub (Dec 1, 2018).
When you create a new LzmaStream it uses memory of about dictionary*11.5.
You expect that memory to go away when you do LzmaStream.Close() or LzmaStream.Dispose().
However that's not the case, and under certain conditions the .NET memory allocator doesn't free the object until the method that created it has exited, meaning that a single method can easily run out of process memory with a handful of LzmaStream initializations, that are not cleared even when manually calling the Garbage Collector.
The problem was discovered in https://github.com/claunia/DiscImageChef/issues/210
@adamhathcock commented on GitHub (Dec 3, 2018):
What are you saying? You're disposing the LzmaStream but still holding on to that instance? The memory it allocates would be freed once you don't have any pointers to the LzmaStream. I don't believe it uses memory in such a way that it leaks it if the LzmaStream itself is garbage collected.
@claunia commented on GitHub (Dec 31, 2018):
Hi @adamhathcock sorry for late response.
As I explained what I observed is that .NET is not freeing memory in-method.
Should be pretty easy to replicate.
Just create something like this:
Then if you run it thru the profiler you will see that the memory is never released until
CrashMethod()has exited.It also exhibits this behaviour:
And in the end the solution I found was:
So the end result is that the .NET Framework does not free any kind of memory usage that has been allocated until the method that allocates such memory exits. Calling the garbage collector makes no difference in any of its variants.
I'm not particularly sure if it can be solved inside LzmaStream (maybe clearing the dictionary array on close?) but would be good to be documented, as I could not find documentation of this particular framework behaviour anywhere, having to discover it using non-free memory profiling tools.
@claunia commented on GitHub (Dec 31, 2018):
P.S.: happy new year
@adamhathcock commented on GitHub (Jan 3, 2019):
There aren’t any unmanaged resources to consider not any statics so what’s happening is all up to the GC.
I could be mistaken but the memory allocation is necessary in the constructor and isn’t reused. An arraypool could possibly be used but Dispose would need to be explicitly used in any case.
@claunia commented on GitHub (Jan 3, 2019):
If that can help...
If not at least documenting the behaviour, so people know what to except when using the knowingly memory intensive LZMA algorithm.