-
Notifications
You must be signed in to change notification settings - Fork 5k
TypeDescriptor caching blocks unloading of code which uses it from unloadable load context #30656
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
Comments
/cc @janvorli |
Would it make sense to make the caches ALC specific so that converters caches in each context don't leak and wait for collection to occur? [edit] I've just realised that they've internal to a third party assembly so that might not be the best solution but it might still be possible. |
That could also work - not sure which solution is best for perf... |
@vitek-karas I assume this issue is not meeting the 3.0 bar so I marked it as for 5.0 release. Let me know if this is not the case. |
I agree it does not meet 3.0, but I think we should at least consider it for 3.1 - it blocks lot of unloadability scenarios - with no good workaround. |
Just having a look through the code this change might be as simple as changing some |
Talked offline with @vitek-karas and here is a possible action plan forward for this issue:
|
Not seeing this meet the bar for 5.0 at this point either. We haven't seen a ton of interest in this outside of this report. The risk here is substantial as this code has been around for decades now and is a critical piece of windows App models like Winforms and WPF. We'd need to be very careful when touching this not to change behavior nor impact perf substantially. We're not prepared to take that amount of risk at this point in the product. |
@ericstj Correlating the issues between LoadContexts and the TypeDescriptor is definitely too hard to have some feedback after such a short amount of time. Also, considering that .NET 5 is not a LTS, it is probably the best time to make the changes required from this issue. Any later changes would bring just more risks, even if someone had a ton of patience in understanding that the failure reason is the TypeDescriptor. HTH |
We're at the RC stage in 5.0., unfortunately it's too late to jam in a change like this. We still have a year for 6.0, we can put a change in early in 6.0 and let it bake to ensure it's solid before release. Did anyone identify the specific tables impacted? Some tables cannot be made completely weak as they back static API that needs to behave predictably. Others can be made weak easily like |
@ericstj I am not aware of other tables. Is it also too late to expose a "free" like method to avoid nasty reflection workarounds? |
Moving to Future as this issue has been around and is not critical to fix in 7.0. |
@ericstj sorry to resurrect the old thread 😄 |
cc @steveharter |
thanks for the comment @ericstj! this is a good point, I think using |
I've never used that before, but it seems like it should. Can we guarantee the Type object will stay alive so long as the assembly is not unloaded? Is the unloading something that needs to be done explicitly, and not just something that will happen on its own when no strong references remain? |
I believe so. As far as I understand the design, the type instance for collectible types is allocated by LoaderAllocator and stored in its m_slots table. So it will be alive until MethodTable is alive and it is alive until the LoaderAllocator is alive.
unloading of the AssemblyLoadContext is explicit, yes - the AssemblyLoadContect.Unload api should be called, before that all assemblies, their code and type will remain in memory |
The implementation of
TypeDescription
andTypeConverter
uses internal caches which hold strong references to theType
object. These remain even after the descriptors and converters are released by the user code.If these types come from collectible assemblies (either dynamic types, or custom unloadable AssemblyLoadContext), this prevents unloading of such assembly.
This is exaggerated by the fact that
TypeConverter
is used byNewtonsoft.Json
during serilization or deserialization of JSON. This is VERY common in user code. This effectively means that any app which uses plugins and wants to be able to unload the plugins successfully would have to prevent all such plugins from using Newtonsoft.Json serialization on objects from the plugin.This is basically a feature ask to modify all the internal caches in
TypeDescriptor
/TypeConverter
implementation to be based on weak references, so that it's possible to collect the types.Customer issue which ran into this, with detailed analysis of what happens: https://github.com/dotnet/coreclr/issues/26271
It was possible to workaround in this case by loading the
ComponentModel
assemblies many times into separate ALCs, but that comes with large performance penalty and is not an obvious solution to the problem.The text was updated successfully, but these errors were encountered: