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菜单里选…

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加…

《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;那就是将任务的…

用 MAUI 在Windows 和 Linux 绘制 PPT 图表

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

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

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

Java中ArrayList,LinkedList,Vector三者的异同点及其使用场景和ArrayList的一些常用方法

相同点&#xff1a;三者存储的都是有序&#xff0c;可重复的数据。 异&#xff1a; ①&#xff1a;ArrayList底层存储类型是Object数组&#xff0c;而LinkedList底层是双向链表 ②&#xff1a;ArrayList和Vector调用创建空参构造器创建对象时&#xff0c;默认的size是10&…

第二百四十六节,Bootstrap弹出框和警告框插件

Bootstrap弹出框和警告框插件 学习要点&#xff1a; 1.弹出框 2.警告框 本节课我们主要学习一下 Bootstrap 中的弹出框和警告框插件。 一&#xff0e;弹出框 弹出框即点击一个元素弹出一个包含标题和内容的容器。 基本用法 注意&#xff1a;必须在js结合popover()方法使用 da…

Intellij IDEA2017 的控制台里不识别maven命令问题处理

2019独角兽企业重金招聘Python工程师标准>>> cmd里运行 mvn -v可以显示出maven的版本信息&#xff0c;可是在IDEA的控制台里却提示不识别maven命令&#xff0c;此情况以管理员的身份运行IDEA即可。 转载于:https://my.oschina.net/u/2364025/blog/1788797

使用IDEA 提交代码到svn

2019独角兽企业重金招聘Python工程师标准>>> 新手第一次使用教程&#xff1a; 一、安装svn TortoiseSVN是个客户端&#xff0c;需要安装VisualSVN服务端。 二、IDEA配置&#xff08;Ctrl alt S&#xff09; 需要配置服务端svn.exe文件。 三、上传代码 svn路径&…

如何在 BackgroundService 获取 ASP.NET Core 启动地址

前言上次&#xff0c;我们介绍了《如何获取 ASP.NET Core 启动地址》。但是&#xff0c;如果要在 BackgroundService 中获取启动地址可不那么容易&#xff0c;因为 BackgroundService 在 app 启动前就开始执行了:var builder WebApplication.CreateBuilder(args); builder.Ser…

016-Spring Boot JDBC

一、数据源装配 通过查看代码可知&#xff0c;默认已装配了数据源和JdbcTemplate System.out.println(context.getBean(DataSource.class)); System.out.println(context.getBean(JdbcTemplate.class)); 1.1、环境搭建 主要是pom引用&#xff1a;spring-boot-starter-jdbc、增加…

分库分表和 NewSQL 到底怎么选?

文章来源&#xff1a;【公众号&#xff1a;CoderW】 目录 背景 分表 分库 分库分表的成本 NewSQL NewSQL 平滑接入方案 NewSQL 真的有那么好吗&#xff1f; NewSQL 的应用 分库分表和 NewSQL 到底怎么选&#xff1f; 背景 曾几何时&#xff0c;“并发高就分库&#xff…

jQuery/javascript实现简单网页计算器

1 <html>2 <head>3 <meta charset"utf-8">4 <title>jQuery实现</title>5 <script src"jquery.js"></script>6 7 <style type"text/css">8 table{background-color:pink;width:300px;height…