缘起
前一阵子,平台在换基线,底层接口变了很多,因此引出了至少 20000
个编译错误。在加班改完这些编译错误后,没想到又遇到了一个诡异的编译错误。而且之前还解决过类似的编译错误,但是这次却没能第一时间找出罪魁祸首。一起看看这是一个什么编译错误吧。
在前面两篇文章中(这里,这里)总结了使用 windbg
和 IDA
找出 cvtres.exe
报错的根本原因,并把一些细节问题弄清楚了。但是还剩下一个小细节没有深究 —— 如果启动 cvtres.exe
的时候没有指定全路径,windbg
会报系统找不到指定的文件的错误。当时只是根据经验判断需要使用完整路径,但是为什么只使用文件名不行呢?今天就把这个问题也格尽。
说明: 写完本文,我犹豫了很久要不要发表出来。因为这个问题其实很简单(在设置
PATH
环境变量时,路径多加了双引号)。但是当时的我真的是当局者迷,完全没意识到这个问题,导致花费了很长时间。process monitor
,gflag
,IDA
,windbg
,轮番上场,甚至都调试起windbg
来了(嗯,你没看错,不是用windbg
调试,而是调试windbg
),好一阵忙活,中间还走了很多弯路(自以为是的在错误的函数中下断)。最后幡然醒悟,原来真理就在那躺着,静静的等着被发现。之所以决定发出来有几点原因:
- 介绍了让进程自动中断到调试器中的方法,甚至是让一个调试器自动中断到另外一个调试器中的方法。
- 介绍了只对特定线程设置断点的方法、使用
wt
追踪函数调用的方法等。- 提醒自己,在调试过程中一定要保持清醒的头脑。
没耐心的朋友直接跳到最后即可。
前两篇文章 part1 和 part2 基本上理清了 IsSplitter()
运行缓慢的原因 —— 在函数内部使用了带 Compile
选项的正则表达式。
但是没想到在 IsSplitter()
内部使用不带 Compiled
选项的正则表达式,整个程序运行起来非常快,跟静态函数版本的运行速度不相上下。又有了如下疑问:
Compiled
选项实例化的 Regex
速度会这么快?Regex
变量从局部改成全局变量后运行速度有了极大提升?除了避免重复实例化,还有哪些提升?PerfView
收集到的采样数据,大部分发生在 MatchCollections.Count
内部,极少发生在 Regex
的构造函数内部?(使用带 Compiled
选项的正则表达式的时候)Regex.IsMatch()
是如何使用缓存的?Regex
对象会使用正则表达式引擎内部的缓存吗?本文会继续使用 Perfview
抓取一些关键数据进行分析,有些疑问需要到 .NET
源码中寻找答案。在查看代码的过程中,发现有些逻辑单纯看源码不太容易理解,于是又调试跟踪了 .NET
中正则表达式相关源码。由于篇幅原因,本篇不会介绍如何下载 .NET
源码,如何调试 .NET
源码的方法。但是会单独写一篇简单的介绍文章 。
我在上一篇文章《性能优化 | 记一次 .NET 程序的性能优化实战(1)—— 使用 process explorer 快速定位问题代码》中用 process explorer
定位到了导致程序运行缓慢的原因——使用了 .NET
中的正则表达式。.NET
中的正则表达式真这么慢吗?带着疑问,开始了本次的探索之旅。喜欢刨根问底的小伙伴儿快来一起看看吧!