记一次 .NET某道闸收费系统 内存溢出分析

news2024/12/25 13:01:53

一:背景

1. 讲故事

前些天有位朋友找到我,说他的程序几天内存就要爆一次,不知道咋回事,找不出原因,让我帮忙看一下,这种问题分析dump是最简单粗暴了,拿到dump后接下来就是一顿分析。

二:WinDbg 分析

1. 程序为什么会暴

程序既然会爆,可能是虚拟地址受限,也可能是系统内存不足,可以用 !address -summary 观察下。


0:037> !address -summary
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unknown>                               866          53577000 (   1.302 GB)  69.38%   65.11%
Image                                  2244          16ee2000 ( 366.883 MB)  19.09%   17.91%
Heap                                    222           8adc000 ( 138.859 MB)   7.23%    6.78%
Free                                    460           7e14000 ( 126.078 MB)            6.16%
Stack                                   255           5150000 (  81.312 MB)   4.23%    3.97%
TEB                                      85             db000 ( 876.000 kB)   0.04%    0.04%
Other                                    20             79000 ( 484.000 kB)   0.02%    0.02%
PEB                                       1              3000 (  12.000 kB)   0.00%    0.00%
...
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT                             2900          64906000 (   1.571 GB)  83.72%   78.57%
MEM_RESERVE                             793          138d6000 ( 312.836 MB)  16.28%   15.28%
MEM_FREE                                460           7e14000 ( 126.078 MB)            6.16%
...

从卦中可以明显的看出,这又是一例经典的32bit程序受到了2G的内存限制,按往期经验来说解决办法比较简单,改成大地址或者x64即可。

哈哈,既然要分享这篇,自然就不是这么简单的事情,这需要我们排查这个溢出是不是程序的bug导致的,如果是那还得继续找原因。

2. 是程序bug导致的吗

要想搞清楚这个问题,需要去分析各处的内存占用,比如托管堆,可以用 !eeheap -gc 观察。


0:037> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x49fd10a8
generation 1 starts at 0x49fd1000
generation 2 starts at 0x03381000
ephemeral segment allocation context: none
 segment     begin  allocated      size
03380000  03381000  0437ff88  0xffef88(16773000)
23e60000  23e61000  24e5ff88  0xffef88(16773000)
0b510000  0b511000  0c50ff88  0xffef88(16773000)
...
7be20000  7be21000  7cbbdb60  0xd9cb60(14273376)
49fd0000  49fd1000  4afcfe08  0xffee08(16772616)
Large object heap starts at 0x04381000
 segment     begin  allocated      size
04380000  04381000  04a67b50  0x6e6b50(7236432)
Total Size:              Size: 0x39738ad4 (963873492) bytes.
------------------------------
GC Heap Size:    Size: 0x39738ad4 (963873492) bytes.

从卦中可以看到,托管堆占用963M,并且产生了很多的16M的segment,这就表明当前的托管堆吃掉了内存,接下来的问题是为什么托管堆吃了那么多的内存呢?那就只能用 !dumpheap -stat 去观察下托管堆的对象布局咯。


0:037> !dumpheap -stat
Statistics:
      MT    Count    TotalSize Class Name
...
717c8b4c   264594     11642136 System.Threading.ExecutionContext
717cd044   265930     13034088 System.Collections.Hashtable+bucket[]
717ccff4   265854     13824408 System.Collections.Hashtable
71761c34   268005     17152320 System.Threading.OverlappedData
70d73c10   264469     26446900 System.Net.Sockets.OverlappedAsyncResult
717cdd04   280225    293649193 System.Byte[]
013a9f98   269886    540566904      Free
Total 3880354 objects

从卦中可以看到当前托管堆有 26.8w 的 OverlappedData 对象,这是一个非常明显的异常信号,熟悉这块的朋友应该知道,这个东西常常和异步打交道,也就表示当前程序可能有高达 26.8w 的异步请求可能没有得到响应,要想找到这个答案,就需要对 OverlappedData 进行穿刺。

3. OverlappedData 穿刺检查

OverlappedData 穿刺的目的就是要活检内部的 AsyncCallback 回调函数,看看到底是良性还是恶性的,相关命令如下:


0:037> !dumpheap -stat
...
34f38ac4 71761c34       64         
34f39088 71761c34       64   
...
0:037> !mdt 34f39088
34f39088 (System.Threading.OverlappedData)
    m_asyncResult:33e8aafc (System.Net.Sockets.OverlappedAsyncResult)
    m_iocb:03c077a0 (System.Threading.IOCompletionCallback)
    ...
    m_nativeOverlapped:(System.Threading.NativeOverlapped) VALTYPE (MT=7176dfe0, ADDR=34f390b0)
0:037> !mdt 33e8aafc
33e8aafc (System.Net.Sockets.OverlappedAsyncResult)
    m_AsyncObject:03c71d44 (System.Net.Sockets.Socket)
    m_AsyncState:33e8aaec (xxx)
    m_AsyncCallback:03e8f214 (System.AsyncCallback)
    ...
0:037> !mdt 03e8f214
03e8f214 (System.AsyncCallback)
    _target:03c065a8 (xxx)
    _methodPtr:19432480 (System.IntPtr)
0:037> u 19432480
19432480 e933932102      jmp     1b64b7b8
19432485 5f              pop     edi
...
0:037> !ip2md 1b64b7b8
MethodDesc:   131605ac
Method Name:  xxxDevices.ReceiveCallback(System.IAsyncResult)

卦中的信息量还是蛮大的,可以看到这是一个和 Socket 相关的异步函数,并且也成功找到了 xxxDevices.ReceiveCallback 回调函数,接下来就是检查下这个方法附近的业务逻辑,由于代码会涉及到一些隐私,我就多模糊一点,请见谅,截图如下:

仔细阅读这段代码,他是想用异步的方式一次次的用byte[1024]去丈量一段可能的大数据,直到这个 Stream 不能再读了,所以用了 if (stream.CanRead) 判断。

对 Socket 编程比较熟悉的朋友相信很快就能发现问题,判断 Stream 中的数据是否读完应该用 DataAvailable 属性,而不是 CanRead,比如下面这段正确的代码:

最后再贴VS中对 CanReadDataAvailable 属性的解释。


//
// Summary:
//     Gets a value that indicates whether the System.Net.Sockets.NetworkStream supports
//     reading.
//
// Returns:
//     true if data can be read from the stream; otherwise, false. The default value
//     is true.
public override bool CanRead { get; }

//
// Summary:
//     Gets a value that indicates whether data is available on the System.Net.Sockets.NetworkStream
//     to be read.
//
// Returns:
//     true if data is available on the stream to be read; otherwise, false.
//
public virtual bool DataAvailable { get; }

三:总结

这个事故非常有意思,一个简简单单的 CanRead 误用就对程序造成了毁灭性的打击,这也警示大家在用某个属性某个方法前,一定要先搞清楚它到底是怎么玩的。

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

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

相关文章

移动web开发流式布局

1.0 移动端基础 1.1 浏览器现状 PC端常见浏览器&#xff1a;360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器、搜狗浏览器、IE浏览器。 内核&#xff1a; 浏览器内核备注Safariwebkitwebkit内核是苹果公司开发的一款渲染引擎&#xff0c;目前已被很多手机厂商所采…

Java开发的审批流系统,前端使用vue,支持常态化工作审批流程

一、项目形式 springbootvueactiviti集成了activiti在线编辑器&#xff0c;快速开发平台&#xff0c;可插拔工作流服务。 二、项目介绍 本项目拥有用户管理&#xff0c;部门管理&#xff0c;代码生成&#xff0c;系统监管&#xff0c;报表&#xff0c;大屏展示&#xff0c;业…

文心一言使用分享

ChatGPT 和文心一言哪个更好用&#xff1f; 一个直接可以用&#xff0c;一个还需要借助一些工具&#xff0c;还有可能账号会消失…… 没有可比性。 通用大模型用于特定功能的时候需要一些引导技巧。 import math import time def calculate_coordinate(c, d, e, f, g, h,…

一套可以替代人工的Cnc机床自动上下料机器人

Cnc机床自动上下料|整体解决方案 CNC机床自动上下料是指通过自动化设备和系统&#xff0c;实现CNC机床在加工过程中自动进行上下料操作。这种自动化系统通常包括自动送料机和卸料机&#xff0c;可以根据加工工件的尺寸和形状自动调整上下料的位置和角度&#xff0c;从而提高生产…

SpringCloud整合Zookeeper代替Eureka案例

文章目录 本期代码下载地址zookeeper简介zookeeper下载安装新建服务提供者测试 新建消费者测试 本期代码下载地址 地址:https://github.com/13thm/study_springcloud/tree/main/days4 zookeeper简介 zookeeper是一个分布式协调工具&#xff0c;可以实现注册中心功能 关闭Lin…

VMware Workstation Pro虚拟机搭建

下载链接&#xff1a;Download VMware Workstation Pro 点击上方下载&#xff0c;安装过程很简单&#xff0c;我再图片里面说明 等待安装中。。。。。是不是再考虑怎样激活&#xff0c;我都给你想好了&#xff0c;在下面这个链接&#xff0c;点赞收藏拿走不谢。 https://downl…

DBA技术栈MongoDB:简介

1.1 什么是MongoDB&#xff1f; MongoDB是一个可扩展、开源、表结构自由、用C语言编写且面向文档的数据库&#xff0c;旨在为Web应用程序提供高性能、高可用性且易扩展的数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当…

ElasticSearch的常用增删改查DSL和代码

es增删改查常用语法 我们日常开发中&#xff0c;操作数据库写sql倒是不可能忘记&#xff0c;但是操作es的dsl语句有时候很容易忘记&#xff0c;特地记录一下方便查找。 DSL语句 1、创建索引 -- 创建索引 PUT /my_index {"mappings": {"properties": {&…

数据结构:链式栈

stack.h /* * 文件名称&#xff1a;stack.h * 创 建 者&#xff1a;cxy * 创建日期&#xff1a;2024年01月18日 * 描 述&#xff1a; */ #ifndef _STACK_H #define _STACK_H#include <stdio.h> #include <stdlib.h>typedef struct stack{int data…

查找局域网树莓派raspberry的mac地址和ip

依赖python库&#xff1a; pip install socket pip install scapy运行代码&#xff1a; import socket from scapy.layers.l2 import ARP, Ether, srpdef get_hostname(ip_address):try:return socket.gethostbyaddr(ip_address)[0]except socket.herror:# 未能解析主机名ret…

Leetcode2207. 字符串中最多数目的子字符串

Every day a Leetcode 题目来源&#xff1a;2207. 字符串中最多数目的子字符串 解法1&#xff1a;贪心 一次遍历 设 pattern 的第一个字符为 x&#xff0c;第二个字符为 y。 根据题意&#xff0c;x 插入的位置越靠左&#xff0c;答案的个数越多&#xff1b;y 插入的位置越…

大数据StarRocks(八):集群扩缩容

一、FE扩缩容 StarRocks FE 节点分为 Follower 节点和 Observer 节点。Follower 节点参与选举投票和写入&#xff0c;Observer 节点只用来同步日志&#xff0c;扩展读性能。 注意&#xff1a; 所有 FE 节点的 http_port 必须相同。Follower FE 节点&#xff08;包括 Leader …

大数据工作岗位分析

前言&#xff1a;随着大数据需求的增多&#xff0c;许多中小公司和团队也新增或扩展了大数据工作岗位&#xff1b;但是却对大数据要做什么和能做什么&#xff0c;没有深入的认识&#xff1b;往往是招了大数据岗位&#xff0c;搭建起基础能力后&#xff0c;就一直处于重复开发和…

K8S Informer机制原理解读 | 架构设计

在Kubernetes系统中&#xff0c;组件之间通过HTTP协议进行通信&#xff0c;在不依赖任何中间件的情况下需要保证消息的实时性、可靠性、顺序性等。那么Kubernetes是如何做到的呢&#xff1f;答案就是Informer机制。Kubernetes的其他组件都是通过client-go的Informer机制与Kuber…

Git入门详细教程

一、Git概述&#x1f387; Git官网 Git是一个开源的分布式版本控制系统&#xff0c;用于跟踪文件的变化和协作开发。它允许多个开发者在同一项目中共同工作&#xff0c;并能够有效地管理代码的版本和历史记录。Git可以帮助开发团队更好地协作&#xff0c;追踪代码变更&#xf…

Linux shell编程学习笔记40:stat命令

程序员必备的面试技巧 “程序员必备的面试技巧&#xff0c;就像是编写一段完美的代码一样重要。在面试战场上&#xff0c;我们需要像忍者一样灵活&#xff0c;像侦探一样聪明&#xff0c;还要像无敌铁金刚一样坚定。只有掌握了这些技巧&#xff0c;我们才能在面试的舞台上闪耀…

深入探究 JavaScript 中的 String:常用方法和属性全解析(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Vision Transformer(VIT)模型介绍

计算机视觉 文章目录 计算机视觉Vision Transformer&#xff08;VIT&#xff09;Patch EmbeddingsHybrid ArchitectureFine-tuning and higher resolutionPyTorch实现Vision Transformer Vision Transformer&#xff08;VIT&#xff09; Vision Transformer&#xff08;ViT&am…

算法笔记 #3

2024年1月18日 Q1&#xff1a;搜索二叉树 A&#xff1a;查找&#xff0c;左子树比根几点小&#xff0c;右子树比根大。 删除&#xff1a;1&#xff09;搜索删除的目标节点&#xff0c;记录其父节点&#xff1b; 2&#xff09;左右孩子都为空&#xff0c;直接删掉&#xff1b;…

【2023地理设计组一等奖】城市业态基因图谱与城市风格感知

作品介绍 1 设计思路 1.1 作品背景 随着城市化进程不断推进,城市的餐饮、购物、休闲和文化业态成为城市发展中的重要组成部分,深刻影响着城市经济社会发展和居民生活,塑造了城市的外在形象和内在风格,形成了各具特色的城市发展特征。因此,在区域和全国尺度上研究城市业态…