我和其中一个客户使用我的软件时遇到了死胡同。在我们销售的产品的约40份(使用VB.NET 2005在.NET 2.0中编程的应用程序)中,大约2份没有响应,1核心的双核CPU停留在100%(程序仅使用1核心)
最合乎逻辑的猜测是导致此行为的无限循环,但是数千行代码具有许多循环。这就是我得到的所有信息;现在,您如何建议我调试此问题?
编辑: 基本上,该软件负责计算使用其他设备(例如PC等)所花费的信用额。它是一个Cybercafe管理程序,并且间歇性地失败,即它在失败时减去信用。它还在后台执行其他操作,例如检查是否是时候创建数据库备份等。
编辑: 解决了。这是最不可能的问题。我用作DBMS的Access数据库引擎实际上是我的应用程序中存在问题的部分。在其中一个表中使用一排JUST ONE FRIGGIN ROW很困难。我无法删除它,或以其他方式在任何其他表中添加与该行相关的记录;当我尝试使用该行时,即使是MS Access 2007也会导致CPU达到100%!
一个简单的“压缩和修复”命令修复了一切。我想每次我的应用程序启动时都会发出该命令。这样可以防止再次发生这种情况。
感谢WinDbg,我可以找到问题所在。我建议大家学习如何使用它,因为它可以节省时间。
答案 0 :(得分:7)
在目标计算机上安装windbg(Windows调试程序)。调用调试器,并附加到可疑进程,运行程序,然后等待问题发生。出现问题时,请在调试器命令行中调用以下命令
!失控
这将显示您的哪些线程在大多数时间消耗。然后从该线程中获取几个消耗大部分cpu资源的线程堆栈。
以下是一个例子:
0:015> !runaway
用户模式时间 线程时间 0:1074 0天0:00:21.637 11:137c 0天0:00:02.792 4:12c8 0天0:00:00.530 9:1374 0天0:00:00.046 15:13d0 0天0:00:00.000 14:1204 0天0:00:00.000 13:154c 0天0:00:00.000 12:144c 0天0:00:00.000 10:1378 0天0:00:00.000 8:1340 0天0:00:00.000 7:12f0 0天0:00:00.000 6:12d4 0天0:00:00.000 5:12d0 0天0:00:00.000 3:12c4 0天0:00:00.000 2:12c0 0天0:00:00.000 1:12b4 0天0:00:00.000
现在假设我们想要一个调用堆栈用于列表中的第二个线程,线程11,所以我们首先切换到线程11.这可以通过输入~11s来完成。
0:015> ~11s
eax = 03fbb270 ebx = ffffffff ecx = 00000002 edx = 00000060 esi = 00000000 edi = 00000000 eip = 77475e74 esp = 0572f60c ebp = 0572f67c iopl = 0 nv up ei pl zr na pe nc cs = 001b ss = 0023 ds = 0023 es = 0023 fs = 003b gs = 0000 efl = 00000246 NTDLL KiFastSystemCallRet! 77475e74 c3 ret
现在通过执行kp:
获取此线程的调用堆栈0:011> kp
ChildEBP RetAddr
0572f608 77475620 ntdll!KiFastSystemCallRet
0572f60c 75b09884 ntdll!NtWaitForSingleObject+0xc
0572f67c 75b097f2 kernel32!WaitForSingleObjectEx+0xbe
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Mozilla Firefox 3.1 Beta 1\nspr4.dll -
0572f690 10019a0b kernel32!WaitForSingleObject+0x12
WARNING: Stack unwind information not available. Following frames may be wrong.
0572f6ac 10015979 nspr4!PR_MD_WAIT_CV+0x8b
0572f6c4 10015763 nspr4!PR_GetPrimordialCPU+0x79
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Mozilla Firefox 3.1 Beta 1\xul.dll -
0572f6e0 64d44d6a nspr4!PR_Wait+0x33
0572f708 64dbe67e xul!NS_CycleCollectorForget2_P+0x698a
0572f72c 10019b3f xul!gfxWindowsPlatform::FontEnumProc+0xfd4e
0572f734 10015d32 nspr4!PR_MD_UNLOCK+0x1f
0572f738 1001624b nspr4!PR_Unlock+0x22
0572f754 1001838d nspr4!PRP_TryLock+0x4cb
00000000 00000000 nspr4!PR_Now+0x109d
命令kp将打印参数。可以使用dv。
打印局部变量或者,您可以使用sysinternals中的process explorer。
如果所有这些都不可能,因为它是远程客户端计算机,请安装userdump,它会创建一个转储文件,可以发送给您进行进一步分析。您可以为客户创建批处理文件,以使用正确的参数调用userdump。 Userdump是Microsoft的一个工具,可以从他们的网页下载。
答案 1 :(得分:4)
如果可能,获取进程转储并查看堆栈跟踪 我从来没有这样做但它应该适用于VS / WinDbg和SOS(罢工之子)。 这是关于它的blog post 。
答案 2 :(得分:4)
如果是无限循环,则尝试附加调试器并按下break。 WinDbg非常适合这种情况。
该技术也适用于循环迭代次数过多但最终继续执行其余代码的情况。可以花几分钟重复这个程序来获得一个好的样本。
这项技术为我节省了好几次,也适用于挂起的应用程序:)
答案 3 :(得分:2)
嗯,你需要找出紧密循环的地方。您的客户当时使用该软件做了什么?该软件首先做了什么?
您可能需要考虑在代码中添加大量日志记录,并为客户端提供启用了所有日志记录的副本,以帮助您跟踪他们遇到问题的位置。
答案 4 :(得分:2)
使用log4net之类的记录器,您可以使用postsharp将其引入现有代码库。记录所有方法条目和退出 - 因此您应该找到有缺陷的方法。然后,如果仍然需要,您可以改进日志记录。
看起来这也适用于vb.net,虽然我没有经验。也许this article对你有所帮助。
答案 5 :(得分:2)
你必须非常彻底地采访这些客户。这并不总是那么容易,但它是你缩小问题的唯一机会。
然后仔细添加跟踪,不要忘记在战略要点(或设置AutoFlush)刷新。
但这可能是一个微妙的计时问题,由于追踪延迟而消失......
答案 6 :(得分:1)
单核和多核CPU的行为可能存在问题,例如当后台线程尝试更新UI时。
(而且我承认我在黑暗时代写了一个应用程序,并没有干净地分离背景和UI线程,并在多核CPU成为主流时引起问题。解决方案是调用SetProcessAffinity将应用程序限制为单核心)
如果是这种情况,您应该检查100%CPU是否仅使用特殊类型的CPU,以及使用SetProcessAffinity是否解决了问题。如果是,您知道在代码中查找的位置。
答案 7 :(得分:0)
这可能是一个线程问题吗? “间歇性地失败”使 我想起来了。程序是否接收信号/消息 从外面看,像远程/ DCOM /插座?是进步 与用户中呈现的此类消息相关的信息 接口
我曾经检测到线程问题,因为我总是使用 很多ASSERT。开始时有一个完整性检查ASSERT 通过XML-RPC收到的消息是:
"<?xml "
并且ASSERT覆盖了消息的内存。通过 检查结果是由于缺少锁定 关键部分。这种检测只有可能,因为 这个问题很早就被ASSERT抓住了(而且它 发生得足以经常被发现。)
这不是一个非常明确或有针对性的建议,但我的 建议然后在可能的地方添加ASSERT 影响了线程问题。
请注意,解雇ASSERT并不一定意味着中止 程序或抛出消息框。 ASSERT可以 重定向到日志文件,包括完整堆栈 在ASSERT解雇时跟踪。