PerfView专题 (第三篇):如何寻找 C# 中的 VirtualAlloc 内存泄漏

一:背景

上一篇我们聊到了如何用 PerfView 去侦察 NTHeap 的内存泄漏,这种内存泄漏往往是用 C 的 malloc 或者 C++ 的 new 分配而不释放所造成的,这一篇我们来聊一下由 VirtualAlloc 方法造成的泄漏如何去甄别?

了解 VirtualAlloc 的朋友肯定说, C# 这种高层语言怎么可能会用 VirtualAlloc 呢?即便是 C++ 大概率也不会用这个,其实这么说还是世面见少了,经历的案例太少,接下来我们就来简要聊一聊。

二:C# 中真的会用 VirtualAlloc 吗

常规的 C# 内存分配确实不会直接调用 VirtualAlloc,但那些图形图形的工具方法肯定会直接用的,比如说 Bitmap,如果不信的话,我可以让你眼见为实,先上一段代码。

static void Main(string[] args){for (int i = 0; i < int.MaxValue; i++){Test2();Console.WriteLine(i);}Console.ReadLine();}public static void Test2(){int width = 1000;int height = 1000;Bitmap bitmap = new Bitmap(width, height);string path = @"D:\test\1.jpg";bitmap.Save(path);}

这段代码中我会生成 1000x1000 的图片,接下来用 bp KernelBase!VirtualAlloc 去做一个拦截。

0:009> bp KernelBase!VirtualAlloc
0:009> g
Breakpoint 0 hit
KERNELBASE!VirtualAlloc:
00007ffd`0d53f9e0 4883ec38        sub     rsp,38h
0:000> k# Child-SP          RetAddr               Call Site
00 00000000`001ce828 00007ffc`eaaf4483     KERNELBASE!VirtualAlloc
01 00000000`001ce830 00007ffc`eaaf35fb     gdiplus!GpMemoryBitmap::AllocBitmapData+0x137
02 00000000`001ce870 00007ffc`eaacded1     gdiplus!GpMemoryBitmap::AllocBitmapMemory+0x3f
03 00000000`001ce8b0 00007ffc`eaacddf2     gdiplus!GpMemoryBitmap::InitNewBitmap+0x49
04 00000000`001ce8f0 00007ffc`eaacdf6f     gdiplus!CopyOnWriteBitmap::CopyOnWriteBitmap+0x8a
05 00000000`001ce930 00007ffc`eaace074     gdiplus!GpBitmap::GpBitmap+0x6b
06 00000000`001ce970 00007ffc`357d8143     gdiplus!GdipCreateBitmapFromScan0+0xc4
07 00000000`001ce9d0 00007ffc`357e8eb1     0x00007ffc`357d8143
08 00000000`001ceaa0 00007ffc`357d3288     System_Drawing_Common!System.Drawing.Bitmap..ctor+0x31 [_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs @ 80] 
09 00000000`001ceaf0 00007ffc`357d2974     ConsoleApp7!ConsoleApp7.Program.Test2+0x58 [D:\net6\ConsoleApp1\ConsoleApp7\Program.cs @ 27] 
...

从输出中可以看到在 Program.Test2调用的过程中果然被 VirtualAlloc 拦住了,而区区 200 多个 Bitmap 就已经分配了 1G 个内存,截图如下:

c2d38922d9eee59eb58bee04beebbcb7.png

而此时的 GCHeap 上才区区 1.7M

0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000000002941030
generation 1 starts at 0x0000000002941018
generation 2 starts at 0x0000000002941000
ephemeral segment allocation context: nonesegment             begin         allocated         committed    allocated size    committed size
0000000002940000  0000000002941000  0000000002ADFFE8  0000000002AE2000  0x19efe8(1699816)  0x1a1000(1708032)
Large object heap starts at 0x0000000012941000segment             begin         allocated         committed    allocated size    committed size
0000000012940000  0000000012941000  0000000012941018  0000000012942000  0x18(24)  0x1000(4096)
Pinned object heap starts at 0x000000001A941000
000000001A940000  000000001A941000  000000001A949C10  000000001A952000  0x8c10(35856)  0x11000(69632)
Total Allocated Size:              Size: 0x1a7c10 (1735696) bytes.
Total Committed Size:              Size: 0x1a2000 (1712128) bytes.
------------------------------
GC Allocated Heap Size:    Size: 0x1a7c10 (1735696) bytes.
GC Committed Heap Size:    Size: 0x1a2000 (1712128) bytes.

非常明显的非托管泄漏。

三:如何用 Perfview 检测

perfview 是一个非常好的运行时检测工具,它也是根据 钩子函数 拦截后看分配量来做一个权重,最终根据权重占比寻找到问题函数调用栈。

ec4b0bfc46aa8360bc70494f5e61106a.png

勾选上 VirtualAlloc 之后就可以点击 Start Collection,5s 之后就会生成一个 统计报表 ,我们点击 Memory -> Net Virtual Alloc Stacks 选项。

6fb39a0b3de22bb9e35202ecc85ca6ce.png

在弹出面板中选择我们的程序,点击 CallTree 面板,清除 GroupPats 分组,截图如下:

2dad7e9a5544c705880cf9be7497484c.png

从面板中可以看到,在内存分配权重总量上,Test2() 占比 97.9%, 说明确实是一个问题,而且是初始化 Bitmap 出来的。

到这里, VirtualAlloc 的泄漏问题就找出来了, 如果用 WinDbg 分析的话,还需要开启 ust 选项,也是记录线程栈,但使用起来相对繁琐。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283714.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[APP]- 找回Xcode7的代码折叠功能

为什么80%的码农都做不了架构师&#xff1f;>>> 原 找回Xcode7的代码折叠功能 升级到Xcode7后&#xff0c;会发现代码折叠功能不见了&#xff0c;这是怎么回事&#xff1f; 其实这个功能还在的&#xff0c;只是苹果默认把这个功能禁掉了&#xff1a;在Xcode菜单里选…

有哪些值得推荐的.NET ORM框架?

前言&#xff1a; 最近有很多同学问我.NET方面有哪些好用的ORM框架&#xff0c;我觉得这方面的介绍网上应该会介绍的比较全面文章&#xff0c;于是我想搜一篇全面的介绍文章发给他们结果我发现网上说来说去基本上就是那几个&#xff0c;于是就有了这篇文章。 什么是ORM? ORM 是…

从S3中导入数据到Dynamodb

本节如果你已经从Dynamodb中导出过数据&#xff0c;而且导出的文件以及被存入S3。文件内部结构会在Verify Data Export File 中描写叙述。我们称之前导出数据的原始表为source table&#xff0c;数据将要被导入的表为destination table。你能够将S3中的导出文件导入到dynamodb的…

HTML5程序开发范例宝典 完整版 (韩旭等著) 中文pdf扫描版

HTML5程序开发范例宝典紧密围绕编程者在编程中遇到的实际问题和开发中应该掌握的技术&#xff0c;全面介绍了利用HTML进行程序开发的各方面技术和技巧。全书共16章&#xff0c;内容包括HTML网页布局、HTML基本元素、HTML高级元素、表单的使用、列表的使用、超链接、表格应用、图…

ASP.NET Core 6框架揭秘实例演示[11]:诊断跟踪的几种基本编程方式

在整个软件开发维护生命周期内&#xff0c;最难的不是如何将软件系统开发出来&#xff0c;而是在系统上线之后及时解决遇到的问题。一个好的程序员能够在系统出现问题之后马上定位错误的根源并找到正确的解决方案&#xff0c;一个更好的程序员能够根据当前的运行状态预知未来可…

Autofac详解

Autofac详解 零、文章目录 一、Autofac详解 1、概述 Autofac是第三方IOC容器&#xff0c;是当前最流行的IOC容器。功能强大&#xff0c;比asp.netcore内置容器强大得多&#xff0c;支持属性注入和方法注入&#xff0c;支持AOP。官网地址&#xff1a;http://autofac.org/源码下载…

与ObjectDataSource共舞

4&#xff0c;ORM组件XCode&#xff08;与ObjectDataSource共舞&#xff09; XCode为了能更方便的解决大部分问题&#xff0c;不得不“屈身”于ObjectDataSource。 先上一个经典例子&#xff08;ObjectDataSourceGridView&#xff09;&#xff08;ObjectDataSource&#xff0…

ASP.NET Core 3.1中使用JWT身份认证

文章目录 0、引言1、关于Authentication与Authorization2、整个认证流程是怎样的&#xff1f;3、开始JWT身份认证 3.1 安装JwtBearer包3.2 安装Swashbuckle.AspNetCore包3.3 添加身份认证相关服务到容器中3.4 添加Swagger服务到容器中3.5 将身份认证加入到管道中3.6 将swagger加…

简单泛型

一般的类和方法&#xff0c;只能使用具体的类型&#xff1a;要么是基本类型&#xff0c;要么是自定义的类。如果要编写可以应用于多种类型的代码&#xff0c;这种刻板的限制对代码的束缚就会很大。----《java Generics FAQ》 多态算是一种泛化机制。例如&#xff0c;将方法的参…

weui-react项目实战新心得

weui-react简介 weui是微信官方制作的一个基础样式UI库&#xff0c;打造与原生微信同样的视觉和交互体验&#xff0c;整个UI库包括网页版和小程序版&#xff0c;网页版包括传统的javascript版和react版本。 个人对react的偏爱超过传统js版本&#xff0c;就用了react版本做为自己…

《ASP.NET Core 6框架揭秘》实例演示[10]:Options基本编程模式

依赖注入使我们可以将依赖的功能定义成服务&#xff0c;最终以一种松耦合的形式注入消费该功能的组件或者服务中。除了可以采用依赖注入的形式消费承载某种功能的服务&#xff0c;还可以采用相同的方式消费承载配置数据的Options对象&#xff0c;这篇文章演示几种典型的编程模式…

实现仿简书选取内容生成分享图片效果

前几天脑子里忽然闪过简书的图片分享效果&#xff0c;感觉很简洁也很漂亮&#xff0c;想着能不能用自己方式实现一下呢&#xff0c;于是今天就有了这篇文章。好了&#xff0c;先看下效果图吧&#xff1a; 项目地址: https://github.com/zhangke301... 欢迎star、issues~ 实现这…

千万级可观测数据采集器--iLogtail代码完整开源

2022年6月29日&#xff0c;阿里云iLogtail开源后迎来首次重大更新&#xff0c;正式发布完整功能的iLogtail社区版。本次更新开源全部C核心代码&#xff0c;该版本在内核能力上首次对齐企业版&#xff0c;开发者可以构建出与企业版性能相当的iLogtail云原生可观测性数据采集器。…

Java8新特性--CompletableFuture

并发与并行 Java 5并发库主要关注于异步任务的处理&#xff0c;它采用了这样一种模式&#xff0c;producer线程创建任务并且利用阻塞队列将其传递给任务的consumer。这种模型在Java 7和8中进一步发展&#xff0c;并且开始支持另外一种风格的任务执行&#xff0c;那就是将任务的…

python list对象

def append(self, p_object): # real signature unknown; restored from __doc__ """ L.append(object) -> None -- append object to end """ passappend函数将字符串插入到列表自身的末尾def clear(self): # real signature unknown; resto…

用 MAUI 在Windows 和 Linux 绘制 PPT 图表

我在做一个图表工具软件&#xff0c;这个软件使用 MAUI 开发。我的需求是图表的内容需要和 PPT 的图表对接&#xff0c;需要用到 OpenXML 解析 PPT 内容&#xff0c;读取到 PPT 图表元素的内容&#xff0c;接着使用 MAUI 渲染层绘制图表元素。图表工具软件需要在 Windows 平台和…

初窥Servlet

1. Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术。sun公司在其API中提供了一个servlet接口&#xff0c;用户若想要发一个动态web资源&#xff0c;只需要完成以下两步即可&#xff1a; 1&#xff09;编写一个servlet&#xff0c;即实现servlet接口的Java类…

聊聊接口性能优化的11个小技巧

前言 接口性能优化对于从事后端开发的同学来说&#xff0c;肯定再熟悉不过了&#xff0c;因为它是一个跟开发语言无关的公共问题。 该问题说简单也简单&#xff0c;说复杂也复杂。 有时候&#xff0c;只需加个索引就能解决问题。 有时候&#xff0c;需要做代码重构。 有时…

三元表达式,递归,匿名函数,内置函数

一 、三元表达式 只应用于条件成立返回一个值&#xff0c;条件不成立返回另一个值。   示例&#xff1a;    nameinput(姓名>>: )    resSB if name alex else NB    print(res) 注&#xff1a;通常使用场合为特别简单一眼读懂的地方。二…

ElasticSearch远程随意代码运行漏洞(CVE-2014-3120)分析

原理 这个漏洞实际上非常easy&#xff0c;ElasticSearch有脚本运行(scripting)的功能&#xff0c;能够非常方便地对查询出来的数据再加工处理。 ElasticSearch用的脚本引擎是MVEL&#xff0c;这个引擎没有做不论什么的防护&#xff0c;或者沙盒包装&#xff0c;所以直接能够运行…