解决复杂应用程序问题时要考虑的首要问题

1、对于反应性事件:“将工程师带到现场,因为这样可以更容易地隔离问题。”

这是我听到的最常见的误解。让我解释一下:大多数复杂的问题都需要深入的调试会话。
收集必要的信息是很容易的,可以远程或由客户完成。但是,调试转储文件可能需要几个小时或几天。由于我们可能无法访问我们的私有符号,也无法与具有特定技术知识的同事协作访问,因此在现场工作实际上会减慢进程。
很多时候,在现场工作的一个重要价值是充当远程工程师的耳目,或者更好地理解我们无法通过电子邮件或电话很好理解的复杂问题。

2、“我们需要代码检查,因为我们的应用程序有性能问题。”

有时我会收到代码评审请求,但实际上,客户需要的是问题隔离。那有什么区别,我怎么知道我需要什么?
代码检查的目标是检查源代码并指出代码中不遵循最佳实践的部分,或者表示安全漏洞的部分,或者还可以针对速度进行优化的部分。
问题隔离的目标是隔离导致特定应用程序症状的问题。例如,崩溃、挂起、内存泄漏和性能瓶颈。
让我解释一下:想象一个ASP.NET应用程序性能不佳的场景。如果我代码审查应用程序,我可能会找到可以优化速度的方法。但是,如果应用程序的性能很慢,因为在数据库端或网络上存在瓶颈,那么通过代码检查获得的性能增益并不能解决问题。最坏的情况是,它甚至可能不明显。
如果您希望确保应用程序不存在通过实现最佳实践可以避免的潜在问题,或者如果您认为可以进一步优化应用程序以获得更高的速度,那么代码检查非常好。但是,只有在应用程序没有遇到问题时有一个基线,才能测量速度增益。重要的是,通常性能的提高不如消除瓶颈那么重要。

3、”因此,在修复这个问题后,性能/内存问题将被规范化,对吗?”

实际情况是,可能会有不同的问题导致相同的症状,如性能低下、挂起或内存问题。
这是什么意思?这意味着在解决了最重要和最明显的问题之后,我们需要监视应用程序,因为其他小问题可能会导致相同的症状。此外,在修复了主要瓶颈之后,这些其他小问题应该变得可见和易于隔离。识别和解决应用程序问题是一个迭代过程。

4、“我们使用的是.NET,所以我不需要担心内存管理。”

如果你有一个纯.NET的应用程序,我倾向于同意。然而,大多数商业应用程序都与本机世界有某种交互,比如C Dlls、COM对象或API调用。

CLR非常适合管理纯.NET应用程序中的内存。如果应用程序正在与本机代码交互,则开发人员有责任确保资源已释放/关闭。

5、我需要收集什么信息?我需要收集多少信息?

在信息不足和信息过多之间有一条细线。对我们来说最重要的是得到正确的信息。当遇到这种症状时,从有问题的应用程序收集一个转储文件是非常有价值的。运行正常时从有问题的应用程序中收集的五个转储文件很可能没有太大帮助。
如果应用程序崩溃,则希望在应用程序崩溃时收集转储文件。如果您在任何其他时间收集转储文件,它将没有来自异常的信息。如果强制收集一个巨大的内核转储文件,则最终将从计算机的所有进程中获得一个巨大的转储文件,但同样,该转储文件不会包含导致应用程序崩溃的异常的信息。

6、“我们需要对体系结构进行检查,因为我们的应用程序存在性能问题。”

这与上文第2项类似。架构评审并不是解决当前问题的最佳方法。
此外,架构评审甚至可能不是解决大多数应用程序问题的正确方法,因为这些应用程序问题通常过于细粒度。这意味着客户的应用程序从架构的角度正确设计,但与架构的设计方式无关的问题。
让我举几个例子。假设您还没有为.NET框架安装影响应用程序的重要更新。或者您的SharePoint应用程序没有释放它正在使用的内部SharePoint对象。在这些例子中,架构评审不会揭示这些问题。

7、有时候,找到合适的起点是最困难的。

想象一下这个场景:
“我们需要一个IIS工程师,因为我的W3WP.EXE占用了太多内存。这可能是一个IIS错误,“用户、管理员和开发人员将如何体验这个问题?

  • 最终用户:我认为浏览器有问题,应用程序很慢。
  • IIS管理员:我认为问题出在ASP.NET应用程序上。
  • 开发人员:ASP.NET应用程序运行良好;问题可能出在数据库方面。
  • DBA:SQL服务器运行良好;我认为瓶颈与网络有关。
  • 网络管理员:网络没有问题。

我们作为开发人员PFEs的目标是帮助我们的客户跨不同的技术隔离问题,并在现场或远程提供不同团队之间的跨组协作。

8、我需要什么技能来帮助我调试应用程序?

如果应用程序需要调试,则不需要知道如何管理或安装产品的工程师。你需要的是一个了解应用程序内部以及如何调试它们的工程师。好消息是,这些知识并不依赖于应用程序。
即使Microsoft工程师以前从未见过您的应用程序,他/她也可以调试您的应用程序。这同样适用于我们自己的产品。
如果在某个时候我们将问题隔离到我们的某个产品上,那么我们就需要产品团队中的一名工程师,因为他/她对产品中的问题和缺陷有很深的了解支持。

9、“我执行了!clrstack和大多数运行很长时间的线程正在尝试从数据库中检索数据。瓶颈可能在数据库方面。”

让我告诉你一件事:我曾经对我们的新工程师或那些想了解更多关于.NET调试的人说,如果你想在.NET调试中胜过,你必须学习本机代码调试,这也暗示了C/C++编程的一些知识。
不相信我?如果你最喜欢的博主只知道.NET调试,那就问问他们.NET调试的情况。
就这么说!clrstack是学习.NET调试的人最喜欢的命令。很酷;您可以看到调用堆栈的托管端,它通常比本机端的级别更高。然而,有时您仍然需要看到本机端才能真正理解线程在做什么,否则,如果只关注托管端,您可能会得出错误的结论。
底线是:如果您想提高.NET调试技能,请进一步了解本机调试。

10、“我的两个服务器是相同的,但问题只发生在服务器XYZ上。”

当对这样的场景进行故障排除时,永远不要假设服务器是相同的。相反,收集数据来证明这一点。
一个很好的开始是运行MPSReport/SPSReport工具。此工具将从每个服务器收集所有信息并进行比较。至少在一个服务器完全相同的情况下,根本的问题是应用程序正在访问其中一个服务器,因此它正在过载。

11、“从事件日志中,我可以看到导致应用程序崩溃且调用堆栈指向Windows的异常。我认为这是一个Windows错误。”

这与上文第7项和一个常见的误解有关。有时从第二次机会呼叫堆栈
异常(应用程序未处理的异常,从而导致应用程序崩溃)将来自Windows的dll作为顶部框架。这是正常的,并不意味着Windows会导致崩溃。

例子:

ChildEBP RetAddr
0013bcd0 7c90de7a ntdll!KiFastSystemCall+0x2
0013bdd0 7c81cdfe kernel32!_ExitProcess+0x62
0013bde4 79f944b0 kernel32!ExitProcess+0x14
0013c00c 79f2c09a mscorwks!SafeExitProcess+0x11b
0013c018 79eff585 mscorwks!DisableRuntime+0xd1
0013c0a8 79011628 mscorwks!CorExitProcess+0x242
0013c0b8 77c39d3c mscoree!CorExitProcess+0x46
0013c0c4 77c39e78 msvcrt!__crtExitProcess+0x29
0013c0d4 77c39e90 msvcrt!_cinit+0xee
0013c0e8 0e68d21e msvcrt!exit+0x12
0013c580 0e256834 testappl!FuTestInterface::init+0x34 <<< This is where you should start the investigation.
0013c5a4 0e1d8c01 testapp!WBNARiskReportInterface::getResults+0x442a

因此,不要认为是ntdll或kernel32导致了这个问题。这些操作系统dll中的api是由于应用程序可能导致的异常而调用的。尝试将最新的应用程序方法调用标识为初始调查点。在上面的例子中,这是testappl!FuTestInterface::init。分析它,如有必要,分析前一帧等。

12、“我们从崩溃的C++应用程序中收集转储文件。我们认为这是堆损坏,所以调用堆栈应该指示罪魁祸首,对吧?”

堆损坏不像以前那样频繁,因为.NET应用程序越来越常见。然而,在COM对象和C DLL的时代,堆损坏是一个典型的问题。
要从实际损坏堆的方法中获取调用堆栈是为了启用页堆,请重新启动应用程序,以便它可以使用新的堆管理器设置并收集转储文件。使用这种方法,您可以轻松地隔离堆损坏问题。
可以使用不同的工具(如Page Heap.exe、GFlags.exe、Application)启用页堆验证者和其他人。某些页堆设置(如完整页堆)在每次内存分配后创建一个只读页,因此每当应用程序试图覆盖缓冲区时,它都会命中只读页,从而导致访问冲突。

原文地址:https://www.cnblogs.com/yilang/p/12170689.html

时间: 2024-11-07 10:10:24

解决复杂应用程序问题时要考虑的首要问题的相关文章

Opencv程序移植时问题及解决,移植成功啦,哈哈

Opencv移植方法:http://blog.csdn.net/b5w2p0/article/details/8976665 我用的是Cmake,最终成功,把路径下生成的so文件拷到开发板的  /lib文件下. 在这之前也可能要移植ffmpge:http://blog.csdn.net/b5w2p0/article/details/38455071 遇到问题多看文章,多试几次最终一定会成功. 现在就可以编译程序啦: <span style="font-size:18px;">

Android应用程序启动时发生AndroidRuntime : ClassNotFoundException for Activity class的解决方法

在android应用程序启动时抛出下面异常导致启动失败:07-09 17:12:35.709: ERROR/AndroidRuntime(3866): Uncaught handler: thread main exiting due to uncaught exception 07-09 17:12:35.719: ERROR/AndroidRuntime(3866): java.lang.RuntimeException: Unable to instantiate activity Com

是什么在.NET程序关闭时阻碍进程的退出?

在平时使用软件或是.NET程序开发的过程中,我们有时会遇到程序关闭后但进程却没有退出的情况,这往往预示着代码中有问题存在,不能正确的在程序退出时停止代码执行和销毁资源.这个现象有时并不容易被察觉,但在另一些情况下却会产生影响软件功能的Bug.本文列举可能影响.NET程序进程退出的因素,并用几个小例子说明这些因素如何导致Form Application和Windows Service的Bug. 一.进程不能退出对于某些Windows Form程序的影响 在传统C/S结构的系统中,客户端会通过Soc

【转】程序崩溃时自动记录minidump的c++类

原帖:程序崩溃时自动记录minidump的c++类 封装了一个C++类,当程序意外崩溃的时候可以生成dump文件,以便确定错误原因. 头文件: //crash_dumper_w32.h #ifndef _CRASH_DUMPER_H_ #define _CRASH_DUMPER_H_ #include <windows.h> class CrashDumper { public: CrashDumper(); ~CrashDumper(); static bool _PlaceHolder()

解决MFC应用程序在调整系统比列放大后出错问题心得

公司有一个屏幕书写的软件,06年开始开发的,至今已八年之久,目前处于维护阶段,在接到这个任务前我也没机会接触这个项目的代码 日前,客户反应在系统比列调整为150%出现界面显示不正常.笔记偏移.笔记画出屏幕崩溃等问题.更坑人的是,经过测试部测试发现在不同的主机上有不同的现象,后来在我的自己的开发机上运行有问题,但是比较少.因为我现任的直属领导就是当前这个项目的主力之一,他也觉得很诡异,让我更诡异的是他居然帮这个任务交给了我. 好吧,硬着头皮上吧,花了三天时间来熟悉代码和软件,在这个过程中发现有时重

程序调试时出现的错误

1.         程序调试时出现的错误: a)         逻辑错误:服务器端的代码. i.              因为服务器端的代码一般是静态的强类型语言,编译器会矫正一些拼写错误. ii.              服务器端的代码出现错误之后,一般可以通过编译器调试代码解决. iii.              服务器端编程要学会使用快捷键,增加编程效率,减少出错概率. b)         拼写细节错误:xml配置文件,html文档流,CSS渲染文件,sql脚本,代码中的字符串

图片--Android有效解决加载大图片时内存溢出的问题

Android有效解决加载大图片时内存溢出的问题 博客分类: Android Android游戏虚拟机算法JNI 尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存. 因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView

VS 中NuGet 尝试还原程序包时出错&quot;*&quot;已拥有为&quot;**&quot;定义的依赖项

之前从Git检出项目以后,项目编译不能通过,发现是缺少依赖的外部插件,于是通过NuGet去获取项目依赖的插件,如何通过NuGet恢复使用的插件请使用NuGet还原项目插件. 但是就是在使用NuGet还原依赖插件的时候,出现了"尝试还原程序包时出错"*"已拥有为"**"定义的依赖项"的错误提示,如下图: 在网上搜索好久也找不到类似的回答,最后无奈,问项目组老大,终于得到了解决方案:更新NuGet插件! 更新NuGet后,问题就解决了,至于如何更新N

Android有效解决加载大图片时内存溢出的问题

尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图, 因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存. 因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source, decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsse