Closed mjacobz closed 4 months ago
NativeAOT libraries don't support unloading.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas See info in area-owners.md if you want to be subscribed.
.NET runtime (including native AOT form factor) does not support unloading.
Tagging subscribers to this area: @vitek-karas, @agocke, @vsadov See info in area-owners.md if you want to be subscribed.
Is this mentioned in the docs? I am not able to find it.
(The author might want to clarify that this is for unloading a dynamically linked NAOT library itself, via dlclose
, rather than assembly unloading from within .NET)
This is for unloading a dynamically linked NAOT library itself, via dlclose
Native AOT doesn't unload assemblies and Native AOT programs compiled to native shared libraries cannot be unloaded via dlclose(). I will add a line to the documentation about this.
I wonder how difficult it would be to support it.
And why is it not supported today. We see that for a simple AOT compiled library, you can indeed unload the library using dlclose(), as long as there are for instance no threads running. We have this AOT compiled library running inside a systemd service on an embedded arm64 SOC, and we cannot keep the library open as it takes resources. But, trying to unload it, using dlcose(), kills the calling systemd executable. We would like to know if there is a plan to fix this in the future (net9 for instance). Or if there are any work arounds.
There is some discussion here: https://github.com/dotnet/corert/pull/7011
TL;DR: the .NET base class libraries are not designed to be unloadable and the runtime is not unloadable either.
We see that for a simple AOT compiled library, you can indeed unload the library using dlclose(), as long as there are for instance no threads running.
This does not work. If you run dlclose on native AOT library and you do not see it crash badly, you are just lucky. There may be background threads running in pretty much all situations (e.g. the finalizer thread). dlclose
won't release all memory allocated by the native AOT library, so you will see a significant memory leak.
TL;DR: the .NET base class libraries are not designed to be unloadable and the runtime is not unloadable either.
Right, clean shutdown of the base class libraries is the main problem. The core runtime (ie GC) can be made unloadable, but it is not interesting without having a clean shutdown path for BCL. We have no plans to fix it.
That’s good to know, we will then try to adapt our solution to live with this limitation. The challenge for us then is to dispose the resources when the lib is done with its stuffs - we face a challenge there as well, on arm64 the even a forced garbage collection doesn’t really release the unused memory, what the next best thing to do if you can’t unload the library and you have a long running process ?
The next best thing to do is to use a separate process (which contradicts the "long running process" requirement).
what the next best thing to do
You may be looking for an API like what's proposed in https://github.com/dotnet/runtime/issues/30885
Encountering an issue with our .net 8 multithreaded library compiled to Native AOT . The client app cannot successfully unload the library using dlclose(), resulting in crashes. This issue occurs specifically when the application is running multiple threads and when the threads are alive.
The code where this issue can be reproduced is listed here in the following repo.
https://github.com/mjacobz/dotnet8aot/tree/main
The AOT compilation can be done using the docker file in the repo and can be tested with the cpp client code.