Win7系统使用dotnet 6时,HttpWebRequest证书链错误如何引发内存泄露?

2026-05-25 17:131阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3200个文字,预计阅读时间需要13分钟。

Win7系统使用dotnet 6时,HttpWebRequest证书链错误如何引发内存泄露?

原文:本文字记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,由于使用 HttpWebRequest 访问一个本地服务,此本地服务开启 https 且验证证书链在此 Win7 系统上错误,导致应用内存泄露问题。

改写后:记录迁移至 dotnet 6 后,Win7 系统上因 HttpWebRequest 访问开启 https 的本地服务,系统上证书链验证出错,引发应用内存泄露。

本文记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,因为使用 HttpWebRequest 访问一个本地服务,此本地服务开启 github.com/dotnet/runtime/ 里翻 dotnet 6 的内存相关的帖子,好在没有找到任何有关联的有帮助的,那就侧面证明了,应该是没有其他人遇到了此问题,这是一个好消息。但也许不是,那就是我是第一个遇到的人。其次,由于我采用的是 dotnet 6.0.1 版本,分发给用户端的不敢那么头铁用刚发布的版本,官方最新的是 dotnet 6.0.4 版本,也许在某个安全更新修复了此问题,安全更新有一些是保密的,也就是说我没有能找到,如果强行去找,可以用 MVP 权限去寻找,但这个响应速度就没有那么快

接下来可以调查的方向如下

  • 是否 dotnet 6 底层带来的问题
  • 是否 dotnet 6.0.1 带来的问题,但在 dotnet 6.0.4 修复了

确认是否 dotnet 6 底层带来的问题刚好在我这个项目上,没有那么麻烦。我对比测试了在 Win10 的设备上,发现没有内存泄露。刚好 Xx 应用是从 .NET Framework 迁移过来的,现在改改代码还能跑 .NET Framework 的版本,于是也就同步在出现问题的 Win7 上跑 .NET Framework 的版本,结果发现在 Win7 上使用 .NET Framework 版本没有任何问题。于是大概可以确定,这和 dotnet 6 底层是有所关联,但不能说这是 dotnet 6 底层的锅

接下来确定是否 dotnet 6.0.1 带来的问题,但在 dotnet 6.0.4 修复了的问题。我在此出现问题的 Win7 上,使用 dotnet 6.0.4 版本代替原先的 6.0.1 版本,好在 dotnet 6 是不需要安装的,替换文件即可。结果依然存在内存泄露,这是一个坏消息。也就是说也许我是第一个遇到此问题的人,或者说这是一个官方也不知道的问题。我就尝试去面向群编程,询问了几位大佬是否遇到过此问题,然而所有的回答都和本次遇到的不是相同的问题,且没有一位大佬遇到 dotnet 6 底层的内存泄露问题,这也算是好消息

回到测试 dotnet 6 底层带来的问题上,既然对比了 .NET Framework 和 dotnet 6 两个框架,发现只有在 dotnet 6 框架才出现问题。那可能的原因实际上可以分为三个:

  • 迁移 dotnet 6 过程中,与 .NET Framework 的变更导致的问题
  • 由于 dotnet 6 的机制变更,与 .NET Framework 的不相同,导致的内存回收策略变更的内存泄露问题,例如之前遇到的委托问题
  • 这就是 dotnet 6 底层与 Win7 适配的问题

由于 Xx 应用是一个足够复杂的大型应用,不好定位以上的三个原因。于是采用对比测试法,先创建一个空白的 dotnet 6 的 WPF 应用,在此 Win7 上运行。十分符合预期的,没有内存泄露问题。这能证明,不是那么简单的 dotnet 6 的底层的问题。假如使用空的 dotnet 6 的 WPF 应用也能存在内存泄露,那就能快速定位是 dotnet 6 底层的问题,接下来的步骤就是看是否 WPF 的问题还是 dotnet 更底层的问题,毕竟这个 WPF 是我定制的版本,改了不少的内容

再定位是否迁移 dotnet 6 过程中,与 .NET Framework 的变更导致的问题,我寻找了所有的变更逻辑,逐个还原,或者使用 Fake 逻辑,干掉对应的功能。这个过程相当于一个二分,也就是说如果在干掉了某些功能之后,没有出现内存泄露,那就能定位内存泄露和被干掉的功能相关。完成之后,同时构建出 dotnet 6 和 .NET Framework 两个版本,在此 Win7 上运行。结果依然是 dotnet 6 版本存在内存泄露,而 .NET Framework 版本没有内存泄露

这就证明了原因可能就是 由于 dotnet 6 的机制变更,与 .NET Framework 的不相同,导致的内存泄露。但经过以上的测试,不能说明一定是 内存回收策略变更的内存泄露问题

到这里,其实基本没有了通用套路可以定位的方法了。除了使用二分法,使用二分法逐个模块干掉,看干掉到哪个模块就不存在内存泄露问题。但在此 Xx 应用上使用二分法是一个大工程,再加上内存泄露的判断是需要等待一段时间的。而不是快速就能定位出来,需要通过 VMMap 经过一段时间,按照小时为单位,看 Private Data 的占用,才能了解到是否内存泄露。以上的测试都是可以并行多个同时开始的,尽管每个测试都需要占用半天的时间,好在多个测试并行,以上的测试都在一天内完成。但如果采用二分,那就意味着需要进行串行测试,在上次没有测试完成之前,是无法进行下一个二分的。我就将二分作为最后的方法,继续找找其他的方法

回顾一下,使用 .NET Framework 没有问题,只有 dotnet 6 版本存在内存泄露。通过 dotMemory 和 DUMP 没有找到业务对象的内存泄露,只有某几个 System.Net 命名空间下的对象存在,这些对象不确定是否泄露。更新了 dotnet 6.0.4 也没有解决,也没有搜到帖子,问了大佬们也没有遇到相同的问题,也就是说不是 dotnet 的官方已知问题

既然看到了存在 System.Net 命名空间下的对象存在,那可以猜测是和网络相关的问题,刚才的 dotnet 6 的空 WPF 测试应用只能证明和基础的 dotnet 6 无关,但没有证明和网络模块无关。继续写一个访问网络的 demo 项目,运行发现没有内存泄露问题,看起来此内存泄露问题也不是那么简单能复现,一半是好消息,一半是坏消息。刚好 waterlv 大佬有空回复我了,他告诉我,内存不会无缘无故上涨的,一定是有某些业务逻辑在跑。于是另一个方向是放弃内存的方向,而是调查空闲的时候运行了哪些逻辑

调查某个应用在某段时间运行了哪些逻辑,这是一个 CPU 性能调试问题,相当于调查一段时间内,有哪些逻辑占用了 CPU 资源。调查这个问题最好用的工具就是 dotTrace 工具了。我准备在此 Win7 使用 dotTrace 工具抓 Xx 应用的信息,可惜 dotTrace 工具无法在此 Win7 运行,原因有两个,一个是需要 .NET Framework 4.7 的环境,另一个就是 ETW 准备失败。其中 ETW 准备失败也就无法抓取信息,于是我放弃了 dotTrace 工具

刚好 dotnet 系里面有 dotnet trace 工具,此工具可以完美在 Win7 运行。于是我换用 dotnet trace 工具去抓取,虽然是抓取到了信息,但是 dotnet trace 工具比 dotTrace 工具还是差太远了,差距大概是一个是记事本,一个是 SublimeText 的差距,我没有成功分析出来什么,反而又过去了一天

那换一个方式,通过 DUMP 抓取瞬时的线程调用堆栈,可以看到有很多线程存在,但是基本上都是不在运行的线程。唯一一个看起来稍微相关的堆栈如下

> ntdll.dll!_ZwWaitForMultipleObjects@20() Unknown KERNELBASE.dll!_WaitForMultipleObjectsEx@20() Unknown kernel32.dll!_WaitForMultipleObjectsExImplementation@20() Unknown kernel32.dll!_WaitForMultipleObjects@16() Unknown winhg.mozilla.org/releases/mozilla-release/rev/d9659c22b3c5#l3.347

但是 Xx 应用的内存泄露问题已解决,后续就交给 dotnet 官方

那为什么 .NET Framework 就不存在问题?我继续阅读 dotent 代码和考古 .NET Framework 的代码,看到了这个逻辑是在 .NET Framework 4.6 变更的,也就是本文开始说的内容。刚好 Xx 应用是从 .NET Framework 4.5 升级到 dotnet 6 的,刚好就踩到这个坑

Win7系统使用dotnet 6时,HttpWebRequest证书链错误如何引发内存泄露?

我回顾了本次的调试,用了五天,实际上方向错了。如果开始听 waterlv 大佬,内存不会无缘无故上涨的,一定是有某些业务逻辑在跑,通过调试 CPU 占用的方法,是能在一天内完成。而如上文的调试过程,我调试的方向都是去调试内存,这是不对的。通过 Fiddler 定位是证书问题和定位是 IPC 使用 Https 通讯且证书链损坏,也是定位有哪些业务模块在执行,也就是调试 CPU 占用。通过任务管理器可以看到,大概每间隔 3 秒就有 CPU 占用,也就是说可以认为在 Xx 应用,所有定时任务小于 10 秒的,都是可能导致本次内存泄露的逻辑,我再次阅读 Xx 应用的代码,看到了定时任务小于 10 秒的任务,才只有 5 个。通过二分的方法,逐个定时任务干掉,让这些定时任务一个个都不跑,看哪个定时任务不跑就没有内存泄露,就可以定位到具体的模块。了解到是哪个模块就可以快速了解到具体原因。如果开始使用这个方法,可以在一天内完成,而不是花了两周时间

这就是本次我用 dotnet 6 在 Win7 系统上运行,由于用到了诡异的方式实现的逻辑,导致了触发了一个系统组件或者是 dotnet 底层的坑,让应用内存泄露了,我记录了调试的过程,以及调试使用的工具,让大家看的更加无聊

更多请看

ServicePointManager Class (System.Net) Microsoft Docs

无法连接到一台服务器升级到.NET Framework 4.6 后使用 ServicePointManager 或 SslStream Api

CLR Exception E0434352 Microsoft Docs

EmptyWorkingSet function (psapi.h) - Win32 apps Microsoft Docs

使用 ProcDump 解决 VMM 服务问题 - Virtual Machine Manager Microsoft Docs

ProcDump - Windows Sysinternals Microsoft Docs

GFlags - Windows drivers Microsoft Docs

CertGetCertificateChain function (wincrypt.h) - Win32 apps Microsoft Docs

自由互联博客只做备份,博客发布就不再更新,如果想看最新博客,请到 blog.lindexi.com/


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名[林德熙](blog.csdn.net/lindexi_gd)(包含链接:blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我[联系](mailto:lindexi_gd@163.com)。

本文共计3200个文字,预计阅读时间需要13分钟。

Win7系统使用dotnet 6时,HttpWebRequest证书链错误如何引发内存泄露?

原文:本文字记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,由于使用 HttpWebRequest 访问一个本地服务,此本地服务开启 https 且验证证书链在此 Win7 系统上错误,导致应用内存泄露问题。

改写后:记录迁移至 dotnet 6 后,Win7 系统上因 HttpWebRequest 访问开启 https 的本地服务,系统上证书链验证出错,引发应用内存泄露。

本文记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,因为使用 HttpWebRequest 访问一个本地服务,此本地服务开启 github.com/dotnet/runtime/ 里翻 dotnet 6 的内存相关的帖子,好在没有找到任何有关联的有帮助的,那就侧面证明了,应该是没有其他人遇到了此问题,这是一个好消息。但也许不是,那就是我是第一个遇到的人。其次,由于我采用的是 dotnet 6.0.1 版本,分发给用户端的不敢那么头铁用刚发布的版本,官方最新的是 dotnet 6.0.4 版本,也许在某个安全更新修复了此问题,安全更新有一些是保密的,也就是说我没有能找到,如果强行去找,可以用 MVP 权限去寻找,但这个响应速度就没有那么快

接下来可以调查的方向如下

  • 是否 dotnet 6 底层带来的问题
  • 是否 dotnet 6.0.1 带来的问题,但在 dotnet 6.0.4 修复了

确认是否 dotnet 6 底层带来的问题刚好在我这个项目上,没有那么麻烦。我对比测试了在 Win10 的设备上,发现没有内存泄露。刚好 Xx 应用是从 .NET Framework 迁移过来的,现在改改代码还能跑 .NET Framework 的版本,于是也就同步在出现问题的 Win7 上跑 .NET Framework 的版本,结果发现在 Win7 上使用 .NET Framework 版本没有任何问题。于是大概可以确定,这和 dotnet 6 底层是有所关联,但不能说这是 dotnet 6 底层的锅

接下来确定是否 dotnet 6.0.1 带来的问题,但在 dotnet 6.0.4 修复了的问题。我在此出现问题的 Win7 上,使用 dotnet 6.0.4 版本代替原先的 6.0.1 版本,好在 dotnet 6 是不需要安装的,替换文件即可。结果依然存在内存泄露,这是一个坏消息。也就是说也许我是第一个遇到此问题的人,或者说这是一个官方也不知道的问题。我就尝试去面向群编程,询问了几位大佬是否遇到过此问题,然而所有的回答都和本次遇到的不是相同的问题,且没有一位大佬遇到 dotnet 6 底层的内存泄露问题,这也算是好消息

回到测试 dotnet 6 底层带来的问题上,既然对比了 .NET Framework 和 dotnet 6 两个框架,发现只有在 dotnet 6 框架才出现问题。那可能的原因实际上可以分为三个:

  • 迁移 dotnet 6 过程中,与 .NET Framework 的变更导致的问题
  • 由于 dotnet 6 的机制变更,与 .NET Framework 的不相同,导致的内存回收策略变更的内存泄露问题,例如之前遇到的委托问题
  • 这就是 dotnet 6 底层与 Win7 适配的问题

由于 Xx 应用是一个足够复杂的大型应用,不好定位以上的三个原因。于是采用对比测试法,先创建一个空白的 dotnet 6 的 WPF 应用,在此 Win7 上运行。十分符合预期的,没有内存泄露问题。这能证明,不是那么简单的 dotnet 6 的底层的问题。假如使用空的 dotnet 6 的 WPF 应用也能存在内存泄露,那就能快速定位是 dotnet 6 底层的问题,接下来的步骤就是看是否 WPF 的问题还是 dotnet 更底层的问题,毕竟这个 WPF 是我定制的版本,改了不少的内容

再定位是否迁移 dotnet 6 过程中,与 .NET Framework 的变更导致的问题,我寻找了所有的变更逻辑,逐个还原,或者使用 Fake 逻辑,干掉对应的功能。这个过程相当于一个二分,也就是说如果在干掉了某些功能之后,没有出现内存泄露,那就能定位内存泄露和被干掉的功能相关。完成之后,同时构建出 dotnet 6 和 .NET Framework 两个版本,在此 Win7 上运行。结果依然是 dotnet 6 版本存在内存泄露,而 .NET Framework 版本没有内存泄露

这就证明了原因可能就是 由于 dotnet 6 的机制变更,与 .NET Framework 的不相同,导致的内存泄露。但经过以上的测试,不能说明一定是 内存回收策略变更的内存泄露问题

到这里,其实基本没有了通用套路可以定位的方法了。除了使用二分法,使用二分法逐个模块干掉,看干掉到哪个模块就不存在内存泄露问题。但在此 Xx 应用上使用二分法是一个大工程,再加上内存泄露的判断是需要等待一段时间的。而不是快速就能定位出来,需要通过 VMMap 经过一段时间,按照小时为单位,看 Private Data 的占用,才能了解到是否内存泄露。以上的测试都是可以并行多个同时开始的,尽管每个测试都需要占用半天的时间,好在多个测试并行,以上的测试都在一天内完成。但如果采用二分,那就意味着需要进行串行测试,在上次没有测试完成之前,是无法进行下一个二分的。我就将二分作为最后的方法,继续找找其他的方法

回顾一下,使用 .NET Framework 没有问题,只有 dotnet 6 版本存在内存泄露。通过 dotMemory 和 DUMP 没有找到业务对象的内存泄露,只有某几个 System.Net 命名空间下的对象存在,这些对象不确定是否泄露。更新了 dotnet 6.0.4 也没有解决,也没有搜到帖子,问了大佬们也没有遇到相同的问题,也就是说不是 dotnet 的官方已知问题

既然看到了存在 System.Net 命名空间下的对象存在,那可以猜测是和网络相关的问题,刚才的 dotnet 6 的空 WPF 测试应用只能证明和基础的 dotnet 6 无关,但没有证明和网络模块无关。继续写一个访问网络的 demo 项目,运行发现没有内存泄露问题,看起来此内存泄露问题也不是那么简单能复现,一半是好消息,一半是坏消息。刚好 waterlv 大佬有空回复我了,他告诉我,内存不会无缘无故上涨的,一定是有某些业务逻辑在跑。于是另一个方向是放弃内存的方向,而是调查空闲的时候运行了哪些逻辑

调查某个应用在某段时间运行了哪些逻辑,这是一个 CPU 性能调试问题,相当于调查一段时间内,有哪些逻辑占用了 CPU 资源。调查这个问题最好用的工具就是 dotTrace 工具了。我准备在此 Win7 使用 dotTrace 工具抓 Xx 应用的信息,可惜 dotTrace 工具无法在此 Win7 运行,原因有两个,一个是需要 .NET Framework 4.7 的环境,另一个就是 ETW 准备失败。其中 ETW 准备失败也就无法抓取信息,于是我放弃了 dotTrace 工具

刚好 dotnet 系里面有 dotnet trace 工具,此工具可以完美在 Win7 运行。于是我换用 dotnet trace 工具去抓取,虽然是抓取到了信息,但是 dotnet trace 工具比 dotTrace 工具还是差太远了,差距大概是一个是记事本,一个是 SublimeText 的差距,我没有成功分析出来什么,反而又过去了一天

那换一个方式,通过 DUMP 抓取瞬时的线程调用堆栈,可以看到有很多线程存在,但是基本上都是不在运行的线程。唯一一个看起来稍微相关的堆栈如下

> ntdll.dll!_ZwWaitForMultipleObjects@20() Unknown KERNELBASE.dll!_WaitForMultipleObjectsEx@20() Unknown kernel32.dll!_WaitForMultipleObjectsExImplementation@20() Unknown kernel32.dll!_WaitForMultipleObjects@16() Unknown winhg.mozilla.org/releases/mozilla-release/rev/d9659c22b3c5#l3.347

但是 Xx 应用的内存泄露问题已解决,后续就交给 dotnet 官方

那为什么 .NET Framework 就不存在问题?我继续阅读 dotent 代码和考古 .NET Framework 的代码,看到了这个逻辑是在 .NET Framework 4.6 变更的,也就是本文开始说的内容。刚好 Xx 应用是从 .NET Framework 4.5 升级到 dotnet 6 的,刚好就踩到这个坑

Win7系统使用dotnet 6时,HttpWebRequest证书链错误如何引发内存泄露?

我回顾了本次的调试,用了五天,实际上方向错了。如果开始听 waterlv 大佬,内存不会无缘无故上涨的,一定是有某些业务逻辑在跑,通过调试 CPU 占用的方法,是能在一天内完成。而如上文的调试过程,我调试的方向都是去调试内存,这是不对的。通过 Fiddler 定位是证书问题和定位是 IPC 使用 Https 通讯且证书链损坏,也是定位有哪些业务模块在执行,也就是调试 CPU 占用。通过任务管理器可以看到,大概每间隔 3 秒就有 CPU 占用,也就是说可以认为在 Xx 应用,所有定时任务小于 10 秒的,都是可能导致本次内存泄露的逻辑,我再次阅读 Xx 应用的代码,看到了定时任务小于 10 秒的任务,才只有 5 个。通过二分的方法,逐个定时任务干掉,让这些定时任务一个个都不跑,看哪个定时任务不跑就没有内存泄露,就可以定位到具体的模块。了解到是哪个模块就可以快速了解到具体原因。如果开始使用这个方法,可以在一天内完成,而不是花了两周时间

这就是本次我用 dotnet 6 在 Win7 系统上运行,由于用到了诡异的方式实现的逻辑,导致了触发了一个系统组件或者是 dotnet 底层的坑,让应用内存泄露了,我记录了调试的过程,以及调试使用的工具,让大家看的更加无聊

更多请看

ServicePointManager Class (System.Net) Microsoft Docs

无法连接到一台服务器升级到.NET Framework 4.6 后使用 ServicePointManager 或 SslStream Api

CLR Exception E0434352 Microsoft Docs

EmptyWorkingSet function (psapi.h) - Win32 apps Microsoft Docs

使用 ProcDump 解决 VMM 服务问题 - Virtual Machine Manager Microsoft Docs

ProcDump - Windows Sysinternals Microsoft Docs

GFlags - Windows drivers Microsoft Docs

CertGetCertificateChain function (wincrypt.h) - Win32 apps Microsoft Docs

自由互联博客只做备份,博客发布就不再更新,如果想看最新博客,请到 blog.lindexi.com/


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名[林德熙](blog.csdn.net/lindexi_gd)(包含链接:blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我[联系](mailto:lindexi_gd@163.com)。