我仍在尝试了解正在进行的问题,但它几乎可以概括为 无法卸载AppDomain 。
在ASP.NET WebAPI部署到Azure App Service期间会发生这种情况,我们观察到以下情况:
"在w3wp_12396.dmp中,应用程序的HttpRuntime / LM / W3SVC / 1523308129 / ROOT在关机过程中 。"
分析内存转储我们看到设置了 IsAbortRequested 标志的线程,但它们似乎永远不会完成(此处输出WinDbg !threads
:https://pastebin.com/7CXYcffy)
在内存转储中,我们还看到很多AppDomains" UNLOAD_REQUESTED "阶段,他们似乎永远不会完成卸载(!DumpDomain
的完整输出在这里:https://pastebin.com/kahZQuWN)
Domain 7: 000001c67062c800 LowFrequencyHeap: 000001c67062cff8 HighFrequencyHeap: 000001c67062d088 StubHeap: 000001c67062d118 Stage: UNLOAD_REQUESTED SecurityDescriptor: 000001c6705c5680 Name: /LM/W3SVC/1523308129/ROOT-6-131687140950004974
没有检测到死锁(至少通过WinDbg SOSEX插件' !dlk
命令,通常涵盖大多数死锁情况)
无代码取消线程中止(未调用Thread.ResetAbort()
)
我们现在解决问题的唯一方法是终止进程(停止Azure AppService)。
AppDomain无法卸载的可能原因是什么?
更新即可。在线程堆栈中,我们得到一个提示,它可能与我们的自定义Azure Blob Log4net appender有关,我发现当创建这样的appender时(每个应用程序一次)它会生成具有以下结构的新线程。
while (true)
{
try
{
Flush(); // pseudocode
Thread.Sleep(10000);
}
catch(Exception)
{
}
}
不确定我理解为什么它会导致完全不可阻挡的线程(因为ThreadAbortException
不会被catch停止),但看起来将while (true)
更改为while (!Environment.HasShutdownStarted && !_stopping)
可以解决问题({调用Appender _stopping
时设置{1}},这对于log4net是一种正常关闭的方式)...
答案 0 :(得分:1)
这似乎是一个JIT错误。是的, BUG IN JIT !我发现那里记录了几乎相同的故事:http://labs.criteo.com/2017/04/ryujit-never-ending-threadabortexception/。
要演示此问题,您可以运行以下代码。仅适用于发布模式,仅适用于x64平台(我的目标是.NET 4.5.2)。
除非您手动重新抛出异常,否则您将观察到无限的异常链。为什么它是CLR / JIT中的错误?因为CLR / JIT负责在一个安全的地方注射投掷public void placeOrder(View view) {
Stripe stripe = new Stripe(getApplicationContext(), "pk_test_...");
stripe.createToken(
paymentCard,
new TokenCallback() {
public void onSuccess(Token token) {
// Send token to your server
tok = token;
new StripeCharge(token.getId()).execute();
}
public void onError(Exception error) {
// Show localized error message
Toast.makeText(getApplicationContext(),
error.getLocalizedMessage(),
Toast.LENGTH_LONG
).show();
}
}
);
}
public class StripeCharge extends AsyncTask<String, Void, String> {
String token;
public StripeCharge(String token) {
this.token = token;
}
@Override
protected String doInBackground(String... params) {
new Thread() {
@Override
public void run() {
postData(token);
}
}.start();
return "Done";
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.e("Result",s);
}
}
public void postData(String mToken) {
FormBody.Builder formBuilder = new FormBody.Builder()
.add("amount", "15000")
.add("currency", "gbp")
.add("token", mToken)
.add("shipping", "Road")
.add("receipt_email", "test@test.com")
.add("description", "Purchased from Android");
RequestBody formBody = formBuilder.build();
Request request = new Request.Builder().url(Server.ENDPOINT + "/charge")
.post(formBody)
.build();
Server.getHttpClient().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
switch (response.code()) {
case 200:
JsonObject result = new JsonParser().parse(response.body().string()).getAsJsonObject();
response.body().close();
break;
}
}
});
}
&#34;何时设置了线程的AbortRequested标志。
来自&#34; CLR的Jeffrey Richter引用C#&#34; (违反以下代码):
即使代码捕获
ThreadAbortException
,CLR也不允许 被吞下的例外。换句话说,在捕获结束时 阻止,CLR自动重新抛出ThreadAbortException
异常。
GitHub中的错误:https://github.com/dotnet/coreclr/issues/16122。
ThreadAbortException