I have an application that loads external assemblies which I have no control over (similar to a plugin model where other people create and develop assemblies that are used by the main application). It loads them by creating new AppDomains for these assemblies and then when the assemblies are done being used, the main AppDomain unloads them.
Currently, it simplistically unloads these assemblies by
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
// log exception
}
However, on occasion, exceptions are thrown during the unloading process specifically CannotUnloadAppDomainException. From what I understand, this can be expected since a thread in the children AppDomains cannot be forcibly aborted due to situations where unmanaged code is still being executed or the thread is in a finally block:
When a thread calls Unload, the target
domain is marked for unloading. The
dedicated thread attempts to unload
the domain, and all threads in the
domain are aborted. If a thread does
not abort, for example because it is
executing unmanaged code, or because
it is executing a finally block, then
after a period of time a
CannotUnloadAppDomainException is
thrown in the thread that originally
called Unload. If the thread that
could not be aborted eventually ends,
the target domain is not unloaded.
Thus, in the .NET Framework version
2.0 domain is not guaranteed to unload, because it might not be
possible to terminate executing
threads.
My concern is that if the assembly is not loaded, then it could cause a memory leak. A potential solution would be to kill the main application process itself if the above exception occurs but I rather avoid this drastic action.
I was also considering repeating the unloading call for a few additional attempts. Perhaps a constrained loop like this:
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException exception)
{
// log exception
var i = 0;
while (i < 3) // quit after three tries
{
Thread.Sleep(3000); // wait a few secs before trying again...
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (Exception)
{
// log exception
i++;
continue;
}
break;
}
}
Does this make sense? Should I even bother with trying to unload again? Should I just try it once and move on? Is there something else I should do? Also, is there anything that can be done from the main AppDomain to control the external assembly if threads are still running (keep in mind others are writing and running this external code)?
I'm trying understand what are best practices when managing multiple AppDomains.
I've dealt with a similar problem in my app. Basically, you can't do anything more to force the AppDomain to go down than Unload does.
It basically calls abort of all threads that are executing code in the AppDomain, and if that code is stuck in a finalizer or unmanaged code, there isn't much that can be done.
If, based on the program in question, it's likely that the finalizer/unmanaged code will finish some later time, you can absolutely call Unload again. If not, you can either leak the domain on purpose or cycle the process.
Try to make GC.Collect() if you do not unload the domain.
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException)
{
GC.Collect();
AppDomain.Unload(otherAssemblyDomain);
}
I had similar issues with random behavior for months now, (with some app.Unload even BLOCKING forever ! on some machines)
finally decided to take a big breath and made process isolation.
you can spawn child console process and redirect output
if you need to cancel this is finger in the nose to kill child process and all dependencies / handles.
To an extreme i had to run dedicated cleanup code, and came to solution to create additional process with dedicated cmd line waiting input extracted from console output of initial runner process.
yes this app domain is a real joke and i think this is not a coincidence that it is not anymore in net core.
Related
I have a handler for unhandled exceptions in the App class of my project. It is for the purpose of setting up a Send Feedback button.
App.xaml.cs
private void Application_DispatcherUnhandledException(
object sender, DispatcherUnhandledExceptionEventArgs e)
{
try
{
// Try to collect feedback with dialog.
new ApplicationExceptionDialog(e).ShowDialog();
}
catch
{
MessageBox.Show(
"A problem has occurred with the program:\r\n\r\n" +
e.Exception.Message + "\r\n\r\n" +
"The application will now exit.",
"Application Error",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
finally
{
Application.Current.Shutdown(1); // ← Is this okay?
}
}
Question
Other than handling various exceptions, when all else has failed, what is the proper way to exit the application after an unhandled exception?
Edit
This question is specific to WPF applications. I also have unmanaged code in the application to make logins more secure. I haven't had any problems with it, but I need to make sure that if problems arise, the exit process used is the best option.
The proper way to close a WPF app is to use Application.Shutdown. This instructs all message pumps to stop, and allows your clean-up code (such as closing events) to execute. It also leaves all non-background threads running. In your case, this is probably not what you want.
Since you have an unhandled exception, your system is in an unknown state - you can't assume your closing events will run correctly, and that any running threads will gracefully terminate. As such, I'd suggest using Environment.Exit, this will close the process, and all of it's running threads. But it will run your finally blocks and class finalizers, which are typically used to release acquired resources.
If you think that running finalizers in the current state may result in existing data/resource corruption, or poses any other kind of damage to the system, you should use Environment.FailFast instead. This will instruct the OS to simply kill your process immediately, without running any finalizers. You may want to use this over Environment.Exit, depending on the purpose of your application.
To exit a console application try
Environment.Exit(0);
For a windows application try:
Application.Exit(0);
So I've googled that it freezes because of using unsafe code, and AbortException throws only when control flow returns to managed code. So, in my case I have a native library, called in a thread. So sometimes I can't abort it, because the library is native and the Abort method not just do nothing, but freezes the calling thread.
So, I'd like to solve it.
For example, using a different process should help, but it's very complicated.
So, a less heavy solution is to use ' AppDomains' . But anyway I should create an exe and call it. I tried to generate it in memory like this
var appDomain = AppDomain.CreateDomain("newDomain");
var assemblyBuilder = appDomain.DefineDynamicAssembly(new AssemblyName("myAsm"), AssemblyBuilderAccess.RunAndCollect);
var module = assemblyBuilder.DefineDynamicModule("myDynamicModule");
var type = module.DefineType("myStaticBulder", TypeAttributes.Public);
var methBuilder = type.DefineMethod("exec", MethodAttributes.Static | MethodAttributes.Public);
var ilGenerator = methBuilder.GetILGenerator();
but I found only EMIT-way, it's very very complicated.
Does a superficial solution exist?
This cannot work by design. The CLR has very strict rules about what kind of code can safely be aborted. It is important, beyond the unwise use of Thread.Abort(), plenty of cases where the CLR must abort code, AppDomain unloads being foremost.
The iron-clad rule is that the CLR must be convinced that it is safe to abort the code. It is only convinced of that if the thread is busy executing managed code or is waiting on a managed synchronization object. Your case does not qualify, no way for the CLR to have any idea what that native code is doing. Aborting a thread in such a state almost never not causes problems. Same idea of the danger of Thread.Abort() but multiplied by a thousand. A subsequent deadlock on an internal operating system lock is very likely, utterly undebuggable.
An AppDomain therefore is not a solution either, it cannot be unloaded until the thread stopped running and it won't.
Only thing you can do is isolate that code in a separate process. Write a little helper EXE project that exposes its api through a standard .NET IPC mechanism like a socket, named pipe, memory mapped file, remoting or WCF. When the code hangs, you can safely Process.Kill() it. No damage can be done, the entire process state is thrown away. Recovering tends to be quite tricky however, you still do have to get the process restarted and get it back into the original state. Especially the state restoration is usually very difficult to do reliably.
Recently I worked with an external dll library where I have no influence on it.
Under some special circumstances, a method of this third party dll is blocking and never returning.
I tried to work around this issue by executing this method in a new AppDomain. After a custom timeout, I wanted to Unload the AppDomain and kill all this crap ;)
Unfortunately, it does not work - as someone would expect.
After some time it throws CannotUnloadAppDomainException since the blocking method does not allow aborting the thread gracefully.
I depend on using this library and it does not seem that there will be an update soon.
So can I work around this issue, even if it's not best practice?
Any bad hack appreciated :)
An AppDomain cannot typically solve that problem, it's only good to throw away the state of your program. The real issue is that your thread is stuck. In cases like these, calling Thread.Abort() is unlikely to work, it will just get stuck as well. A thread can only be aborted if it is a "alertable wait state", blocking on a CLR synchronization object. Or executing managed code. In a state that the CLR knows how to safely clean up. Most 3rd party code falls over like this when executing unmanaged code, no way to ever clean that up in a safe way. A decisive hint that this is the case is AppDomain.Unload failing to get the job done, it can only unload the AppDomain when it can abort the threads that are executing code in the domain.
The only good alternative is to run that code in a separate process. Which you can kill with Process.Kill(). Windows do the cleanup. You'd use a .NET interop mechanism to talk to that code. Like named pipes, sockets, remoting or WCF. Plus the considerable hassle of having to write the code that can detect the timeout, kills the process, starts it back up and recovers internal state since you now restart with an uninitialized instance of that 3rd party code.
Do not forget about the real fix. Create a small repro project that reproduces the problem. When it hangs, create a minidump of the process. Send both to the 3rd party support group.
after reading this (scroll down the end to Blocking Issues) I think your only solution is to run the method in a different process - this might involve quite a bit of refactoring and/or a 'host' project (eg Console application) that loads the method in question and makes it easy to call (eg reading args from command line) when launching the new process using the Process class
You can always use background worker, no need to create a new appdomain. This will ensure that you have complete control over the execution of the thread.
However, there is no way to ensure that you can gracefully abort the thread. As the dll is unmanaged, chances are there that it may cause memory leaks. However, spawning a new thread will ensure that your application does not crash when the Dll does not respond.
I am doing a project where I am loading several assemblies during runtime, for each of those assemblies I use reflection to find some specific classes, instantiate them and calling their methods. All this is working fine, but for some of the calls the process encounters a stack overflow which terminates my entire program. I don't have any control over the source code of the assemblies I am loading so I cant change the code I'm executing.
What I have tried to solve the problem:
I assign a thread to do the invocation of the methods and tried to
abort the thread after a timeintervall(I know that this is bad
practice but I cant change the code to terminate friendly). This
however doesn't work, I think the thread is to busy "stackoverflowing"
to handle the Abort-call.
Ive tried reducing the actual memory the thread has access to, this is not even a solution because you cant catch the stackoverflow-exception so my program terminates anyway (just quicker)
Questions:
Can a thread be to busy to be aborted? Is there some way to abort a thread that is having this behaviour?
How can we call code (that we don't have any control over) in a good way?
Thanks in advance!
The recommended procedure in case of "opaque code" is to actually fork a new process and start it. That way you gain two benefits:
If it fails by itself, it's isolated and won't take your main application down as well.
You can safely kill it and it won't cause as much trouble as an aborted thread.
There are already some pretty good threads on this topic on Stack Overflow, but there doesn't really seem to be a concise answer on any of them. My C# console application (running as a Windows service) launches a Java process and manages it (starts/stops/restarts it), but my issue is that I will remote into machines, and see it has started about 20 Java processes sometimes.
This is obviously an issue with my application crashing at some point, and not shutting down the Java process it started. I have hooked "UnhandledExceptionEventHandler" in the AppDomain.CurrentDomain, and I call TerminateProcess() from it (shuts down the active Java process) but this issue is still occuring on occassion.
My application has the Main thread, a TCP Server Thread (which accepts async connections), and a UDP Server Thread. Is there anything else I should be hooking into on top of UnhandledException?
EDIT
It also just occured to me that I have a few Try/Catch blocks in my code that simply write to console, which I never see. Should I just remove these so these are caught by the UnhandledException or add a logger there instead?
First of all you have to change the Console.WriteLine.. lines in you code to Debug.WriteLine.. if you don't want to log, so the output of it will only be on debug.
Second when any exception occurs if you don't know how to handle it or fix it then rethrow it catch { throw; } after logging. I personally do
try
{
...
}
catch (Exception exception)
{
Log(exceptiosn);//log it first or Debug.WriteLine...
#if DEBUG
System.Diagnostics.Debugger.Break();//break at the debugger here.
#endif//DEBUG
throw;
}
After you cleaning up you code, now you can whenever DomainUnhandledException thrown, you can restart your application. an example will be here, The idea is you start a new instance from your application and then terminate the first one. you also define a mutex so only one instance at time will be alive.
Something to consider is whether you want the .NET application to be responsible for the spawned processes. If possible, they might be made responsible for shutting down when no longer receiving input. If the spawned processes are running on other machines I would try to do that anyway because network problems might interfere with sending a shutdown message from the .NET application to the Java processes. Each its own responsibilities.
That said, getting exception handling in the .NET application fixed (especially when you are missing some exceptions) is also important. Make each thread responsible for its exceptions and make sure you log them for easy debugging.