我没有找到在. NET中转储所有线程堆栈的方法。既没有发送给进程的信号,也没有对所有线程的编程访问。我只能通过Thread.CurrentThread访问当前线程。有什么窍门吗?
erhoui1w1#
如果您试图在进程已经运行时获取堆栈转储(la jstack),有两种方法here所述:
有一个鲜为人知但非常有效的工具叫做Managed Stack Explorer,虽然它提供了一个基本的GUI,但是如果您添加到路径中,它可以有效地成为jstack的.NET等价物;那就只需要输入了
mse /s /p <pid>
1.下载并安装适用于您的体系结构(x86/x64/安腾)的Windows调试工具版本1.如果你需要关于Windows函数调用的信息(例如你想跟踪内核调用),下载并安装适当的符号。如果你只是想自己的代码的线程转储,这不是绝对必要的。1.如果您需要行号或任何其他详细信息,请确保将程序集的PDB文件放在调试器可以找到它们的地方(通常您只需将它们放在实际程序集旁边)。1.开始-〉程序-〉Windows调试工具[x64]-〉windbg1.使用菜单将调试器附加到正在运行的进程1.对于.NET 2.0,使用“.loadby sos mscorwks”加载SOS扩展(对于.NET 1.0/1.1,使用“.load sos”)1.使用“!estack”进行线程转储1.使用.“detach”分离我只是发现有必要进行生产线程转储,这对我很有效。希望它有帮助:-)
bis0qfac2#
只是为了保存其他人的麻烦,这里的港口以上的c#:
static void WriteThreadInfo(StringBuilder sw, IEnumerable<Thread> threads) { foreach(Thread thread in threads) { if(!thread.IsAlive) continue; sw.Append(String.Concat("THREAD NAME: ", thread.Name)); sw.Append(GetStackTrace(thread)); sw.AppendLine(); sw.AppendLine(); } } static String GetStackTrace(Thread t) { t.Suspend(); var trace1 = new StackTrace(t, true); t.Resume(); String text1 = System.Environment.NewLine; var builder1 = new StringBuilder(255); for (Int32 num1 = 0; (num1 < trace1.FrameCount); num1++) { StackFrame frame1 = trace1.GetFrame(num1); builder1.Append(" at "); System.Reflection.MethodBase base1 = frame1.GetMethod(); Type type1 = base1.DeclaringType; if (type1 != null) { String text2 = type1.Namespace; if (text2 != null) { builder1.Append(text2); builder1.Append("."); } builder1.Append(type1.Name); builder1.Append("."); } builder1.Append(base1.Name); builder1.Append("("); System.Reflection.ParameterInfo [] infoArray1 = base1.GetParameters(); for (Int32 num2 = 0; (num2 < infoArray1.Length); num2++) { String text3 = "<UnknownType>"; if (infoArray1[num2].ParameterType != null) { text3 = infoArray1[num2].ParameterType.Name; } builder1.Append(String.Concat(((num2 != 0) ? ", " : ""), text3, " ", infoArray1[num2].Name)); } builder1.Append(")"); if (frame1.GetILOffset() != -1) { String text4 = null; try { text4 = frame1.GetFileName(); } catch (System.Security.SecurityException) { } if (text4 != null) { builder1.Append(String.Concat(" in ", text4, ":line ", frame1.GetFileLineNumber().ToString())); } } if (num1 != (trace1.FrameCount - 1)) { builder1.Append(text1); } } return builder1.ToString(); }
我还没有找到一种方法来获得C#中所有托管线程的列表(只有ProcessThreads),所以看起来你确实需要维护你自己感兴趣的线程列表。此外,我发现无法在运行的线程上调用new Stacktrace(t,true),因此添加了暂停和恢复。* 显然,您需要考虑如果您对生产应用进行线程转储,这是否会导致问题 *。顺便说一句,我们已经把这个调用放在我们的应用程序的wcf休息接口,所以它很容易做到。
06odsfpq3#
目前,我所见过的为.NET CLR生成线程转储的最佳工具是DebugDiag。此工具将生成活动CLR线程的非常详细的报告(使用崩溃/挂起分析器)沿着建议。我建议查看下面的.NET DebugDiag tutorial,因为它显示了生产问题后的分析过程。步骤如下:
sgtfey8w4#
如果您需要以编程方式执行此操作(可能希望在CI过程中自动转储),则可以将this answer中的信息用于不同的问题。基本上,使用CLR MD附加到您自己的进程:
using Microsoft.Diagnostics.Runtime; using (DataTarget target = DataTarget.AttachToProcess( Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive)) { ClrRuntime runtime = target.ClrVersions.First().CreateRuntime(); foreach (ClrThread thread in runtime.Threads) { IList<ClrStackFrame> stackFrames = thread.StackTrace; PrintStackTrace(stackFrames); } }
PrintStackTrace在这里留给读者作为练习。
06odsfpq5#
我为我过去工作过的一个项目写了一个转储程序:
void CrashHandler::WriteThreadInfo(StringWriter* sw, ArrayList* threads, String* type) { sw->WriteLine(type); IEnumerator* ie = threads->GetEnumerator(); while(ie->MoveNext()) { botNETThread* bnt = static_cast<botNETThread*>(ie->Current); if(!bnt->IsAlive) continue; sw->WriteLine(String::Concat(S"ORIGIN ASSEMBLY: ", bnt->Assembly->FullName)); sw->WriteLine(String::Concat(S"THREAD NAME: ", (bnt->Name && bnt->Name->Length)?bnt->Name:S"Unnamed thread")); sw->Write(GetStackTrace(bnt->_thread)); sw->WriteLine(); sw->WriteLine(); } } String* CrashHandler::GetStackTrace(Thread* t) { System::Diagnostics::StackTrace __gc * trace1 = __gc new System::Diagnostics::StackTrace(t, true); System::String __gc * text1 = System::Environment::NewLine; System::Text::StringBuilder __gc * builder1 = __gc new System::Text::StringBuilder(255); for (System::Int32 num1 = 0; (num1 < trace1->FrameCount); num1++) { System::Diagnostics::StackFrame __gc * frame1 = trace1->GetFrame(num1); builder1->Append(S" at "); System::Reflection::MethodBase __gc * base1 = frame1->GetMethod(); System::Type __gc * type1 = base1->DeclaringType; if (type1 != 0) { System::String __gc * text2 = type1->Namespace; if (text2 != 0) { builder1->Append(text2); if (builder1 != 0) { builder1->Append(S"."); } } builder1->Append(type1->Name); builder1->Append(S"."); } builder1->Append(base1->Name); builder1->Append(S"("); System::Reflection::ParameterInfo __gc * infoArray1 __gc [] = base1->GetParameters(); for (System::Int32 num2 = 0; (num2 < infoArray1->Length); num2++) { System::String __gc * text3 = S"<UnknownType>"; if (infoArray1[num2]->ParameterType != 0) { text3 = infoArray1[num2]->ParameterType->Name; } builder1->Append(System::String::Concat(((num2 != 0) ? S", " : S""), text3, S" ", infoArray1[num2]->Name)); } builder1->Append(S")"); if (frame1->GetILOffset() != -1) { System::String __gc * text4 = 0; try { text4 = frame1->GetFileName(); } catch (System::Security::SecurityException*) { } if (text4 != 0) { builder1->Append(System::String::Concat(S" in ", text4, S":line ", frame1->GetFileLineNumber().ToString())); } } if (num1 != (trace1->FrameCount - 1)) { builder1->Append(text1); } } return builder1->ToString(); }
您可以使用Process.GetCurrentProcess().Threads来获取线程我知道我spasted托管C++,但它很容易遵循。我采取了线程数组列表,因为出于我的目的,我已经分类了我的线程。是的,我使用了以前编写的堆栈帧代码,因为我当时是MC++的新手:)整个文件是here。这是我以前写的一个Diablo II botting engine。
ttp71kqs6#
System.Diagnostics中有许多方便的类,可以帮助您调试和收集各种跟踪信息,例如StackTrace。有一个不可靠的Process类可以用来获取正在执行的线程的数量,但是细节很少。使用下面的代码段:
Using System.Diagnostics; var threads = Process.GetCurrentProcess().Threads;
好的,在看了更多一点之后,似乎捕获所有当前堆栈的最简单方法是通过一个迷你转储和一个像SOS这样的工具,或者如果你正在运行vista this。祝你好运。
6psbrbz97#
我正在使用https://github.com/odinserj/stdump,这是一个用于探索运行的托管进程的堆栈跟踪的工具。要显示正在运行的程序的堆栈跟踪,请使用其PID或进程名。标准转储12832标准转储w3wp.exe
7条答案
按热度按时间erhoui1w1#
如果您试图在进程已经运行时获取堆栈转储(la jstack),有两种方法here所述:
使用托管堆栈资源管理器
有一个鲜为人知但非常有效的工具叫做Managed Stack Explorer,虽然它提供了一个基本的GUI,但是如果您添加到路径中,它可以有效地成为jstack的.NET等价物;那就只需要输入了
使用风缸
1.下载并安装适用于您的体系结构(x86/x64/安腾)的Windows调试工具版本
1.如果你需要关于Windows函数调用的信息(例如你想跟踪内核调用),下载并安装适当的符号。如果你只是想自己的代码的线程转储,这不是绝对必要的。
1.如果您需要行号或任何其他详细信息,请确保将程序集的PDB文件放在调试器可以找到它们的地方(通常您只需将它们放在实际程序集旁边)。
1.开始-〉程序-〉Windows调试工具[x64]-〉windbg
1.使用菜单将调试器附加到正在运行的进程
1.对于.NET 2.0,使用“.loadby sos mscorwks”加载SOS扩展(对于.NET 1.0/1.1,使用“.load sos”)
1.使用“!estack”进行线程转储
1.使用.“detach”分离
我只是发现有必要进行生产线程转储,这对我很有效。希望它有帮助:-)
bis0qfac2#
只是为了保存其他人的麻烦,这里的港口以上的c#:
我还没有找到一种方法来获得C#中所有托管线程的列表(只有ProcessThreads),所以看起来你确实需要维护你自己感兴趣的线程列表。
此外,我发现无法在运行的线程上调用new Stacktrace(t,true),因此添加了暂停和恢复。* 显然,您需要考虑如果您对生产应用进行线程转储,这是否会导致问题 *。
顺便说一句,我们已经把这个调用放在我们的应用程序的wcf休息接口,所以它很容易做到。
06odsfpq3#
目前,我所见过的为.NET CLR生成线程转储的最佳工具是DebugDiag。此工具将生成活动CLR线程的非常详细的报告(使用崩溃/挂起分析器)沿着建议。
我建议查看下面的.NET DebugDiag tutorial,因为它显示了生产问题后的分析过程。步骤如下:
sgtfey8w4#
如果您需要以编程方式执行此操作(可能希望在CI过程中自动转储),则可以将this answer中的信息用于不同的问题。
基本上,使用CLR MD附加到您自己的进程:
PrintStackTrace在这里留给读者作为练习。
06odsfpq5#
我为我过去工作过的一个项目写了一个转储程序:
您可以使用Process.GetCurrentProcess().Threads来获取线程
我知道我spasted托管C++,但它很容易遵循。我采取了线程数组列表,因为出于我的目的,我已经分类了我的线程。是的,我使用了以前编写的堆栈帧代码,因为我当时是MC++的新手:)
整个文件是here。这是我以前写的一个Diablo II botting engine。
ttp71kqs6#
System.Diagnostics中有许多方便的类,可以帮助您调试和收集各种跟踪信息,例如StackTrace。
有一个不可靠的Process类可以用来获取正在执行的线程的数量,但是细节很少。使用下面的代码段:
好的,在看了更多一点之后,似乎捕获所有当前堆栈的最简单方法是通过一个迷你转储和一个像SOS这样的工具,或者如果你正在运行vista this。
祝你好运。
6psbrbz97#
我正在使用https://github.com/odinserj/stdump,这是一个用于探索运行的托管进程的堆栈跟踪的工具。
要显示正在运行的程序的堆栈跟踪,请使用其PID或进程名。
标准转储12832
标准转储w3wp.exe