.Net程序内存泄漏解析
一、概要
大概在今年三月份的时候突然被紧急调到另外一个项目组解决线上内存泄漏问题。经过两周的玩命奋战终于解决了这个问题这里把心路历程及思路分享给大家。希望可以帮助到各位或现在正遇到这样事情的小伙伴提供一些思路。
二、场景
当部门老大找到我的时候,给我描述了这样一段话。
“目前服务出现了提交内存泄漏的问题,目前分析出来可能是日志组件有大量的日志消息堆积把内存占满导致服务崩溃了。在国内某地区客户的服务器上15000台物联网设备不能正常工作这个问题非常紧急需要马上解决。”
问题描述至此,没有其他可用信息。这时候我先崩溃了...但是任务找到你不能说不行。万一解决了这种重大事故还能在部门老大面前秀一把。
三、思路
(1)分析
Part1,分析日志堆积原因
- 拿到服务器地址去翻出日志文件,查看日志内容;内容基本上都是一些报错情况xxx对象为null,对象转换失败。
- 日志组件的实现也比较糟糕Log对象在每个调用的类里都会重新new
解决方案:
- 修复对象为null的问题并加上空值判断,大概的原因就是json值转换的时候传入的值是null那么就引起这两块的连锁反应。非常值得注意的一点是通常json对象转换的地方都会加入try块去捕获异常在程序里try的捕捉是会对.net程序造成性能影响的所以能用判断规避的尽量不要去触发try机制,程序性能被拖下去其他方面的处理就会变相的削减处理速度变慢那么数据堆积好像就解释的通了。
- 将日志组件重构为单例且线程安全的实现,写入日志的数据结构体是class这里改成struct,考虑的因素是引用类型会存在引用问题再就是考虑的值类型和引用类型在内存中占用的大小是不一样的,而且值类型和引用类型在处理速度上值类型更快。
以为这样就结束了吗?不,当程序改好之后放在测试服务器上跑第二天早上测试部的小姐姐就找到我说异常报错情况是好了,但是内存泄漏还是没解决。
Part2,查找内存泄漏的根本原因
看来Part1的操作仅仅只是修复了一个小bug而已,并不是我所想的那么简单,在日志的查看中还发现log日志中出现“tcp服务拒绝连接XXX异常”。当我看到这些的时候心情糟糕透了....
1.一早我就用Profile把服务程序跑了一遍发现了
- (1)有几个消息队列占用非常大,查阅代码之后发现服务端程序会和15000台物联网设备进行交互的所有数据都会先堆积到这个队列里如果这个队列满了(Queue上限被设定2w)会new新的Queue然后把溢出的部分转到新的Queue里,最可怕的是从队列里取数据的还是单线程处理。
- (2)还会有很多磁盘I/O的操作会存储在应用服务器本机上例如socket通讯的报文和需要转发的内容等等都会进行写入操作。
- (3)逐步调试的时候发现大部分的方法实现都是同步方法,而且框架版本居然是.net freamwork4。
解决方案:
(1)
- 【移除new新队列的机制、删除Main Queue的上限设置改为多线程处理Queue;一切数据堆积的本质就是数据处理不过来所以开辟再多的内存空间都是慢性死亡而已。】
- 【走访物联网硬件部门,询问物联网设备发送数据频率、设备数、单台设备发送单条数据的大小是多少KB;为什么需要了解?这些第一点在程序内记录日志然后统计成走势图能直接观察队列内部的变化开会的时候能给领导具有说服力的证据能看到数据量什么时候陡增、数据大小等;第二点因为这些报文数据需要存在应用服务器本地那么这时候就能计算出写入的数据量有没有超出普通硬盘的写入I/O瓶颈以及网络带宽的占用。】
- 【走访物联网硬件部门2,询问物联网设备socket传输数据时是否有走正常“tcp挥手”流程;为什么?因为socket tcp通讯中,是双工通道那么其中有一端突然断开,另一端会进入“wait”状态不会及时回收tcp连接资源,大家试想一下如果15000台设备高频短连接去操作那么服务端连接队列资源很有可能吃不消。这个时候就需要服务端主动断开“失效”连接及时回收资源“拆除双工通道”以及调整socket连接队列大小。】
(2)磁盘写入报文信息这块,就要用三寸不烂之舌说动项目经理把这块砍掉以节约CPU性能以及减少磁盘I/O,大伙试想一下每次socket通讯进行收发的时候都要去操作一下I/O那是多么恐怖的一件事情;最后沟通结果那个组的项目经理同意砍掉部分模块磁盘写入功能,那么问题来了剩下的怎么办如何将优势进一步扩大?这时候继续查阅项目代码,结果发现socket通讯中“收”、“发”都会操作一次。那么这时候需要做的是将报文积累到一定数量比如说积累1000条报文再一次性写入那么磁盘I/O的操作频率将成倍递减。
(3)最后一个问题,就是讲所有的方法修改为异步方法。这时候就能祭出Task、Async、Await了。但是基于的框架是.net freamwork4的,后来又去查阅MSDN的文档发现.net freamwork4远古框架中还是有这些特性的虽然用法稍微难受点但是还是能优化的。一定要记住一点,开发服务端要有“服务端”思维如果都是同步方法就会被同步阻塞处于“等待处理结果状态”这样的话服务端的并发量是上不去的。
这里虽然没怎么用上的一发大招,但是这里还是分享给大家“注释大法”;注释掉最有可能出问题的地方逐一排查一定能发现问题的所在就是非常的耗时那会我基本每天工作12小时,尤其是公司的远古项目通常“代码烂”、“设计基本没有”、“使用的.net框架版本低”等等,一堆恶心人的事情发生。
(2)工具
- Visual Studio自带的Profile。【可以分析CPU、内存等占用情况;这款比较推荐】
- VMMap【可以分析CPU、内存等占用情况】
- ANTS Performance Profiler【这款工具比较强大能分析调用链路逐级告诉你内存占用的地方以及内存占用大小】
- Window操作系统自带的资源监视器这个不用多说大家都会用。
Part3,总结
基于以上的修改,在测试服务器上稳定运行3周内存稳定在2.9G左右;
一定要记住:
- “遇到任何棘手的事情不要抱怨。”
- “一个优秀的软件工程招聘进来就是解决问题的,而不是制造问题;”
- “对于任务的安排,高手永远都是说出解决问题的期限;到点交东西。而不是支支吾吾说不清楚、退缩。”
- “遇到问题冷静思考,相信自己一定可以的;那怕失败去尝试一下也好。”
- “没解决问题的时候不要说任何话,说什么都像是在找理由。闭上嘴巴去想办法。”
其实解决这个问题时期发生了很多有趣的故事,不过最终还是要解决难啃的问题证明自己,开发学习本身就是一个不断变强的过程“修技术,也修内心”当自己逐渐变强之后也不要鄙视技术不好的同事始终保持一颗学徒的心。
Part4,彩蛋
解决这个问题之后在同部门同事的眼里威望都会有提升(尤其是测试部门的小姐姐,因为她们不用费力的每天去看服务器了),最终解决项目的重大事故部门老大给了机会调到其他省的研发中心当项目经理薪资平移的基础上再上浮百分之十。可见掌握一手救急的技能有多么划算。
.Net程序内存泄漏解析的更多相关文章
- C/C++应用程序内存泄漏检查统计方案
一.前绪 C/C++程序给某些程序员的几大印象之一就是内存自己管理容易泄漏容易崩,笔者曾经在一个产品中使用C语言开发维护部分模块,只要产品有内存泄漏和崩溃的问题,就被甩锅“我的程序是C#开发的内存都是 ...
- Java虚拟机性能管理神器 - VisualVM(6) 排查JAVA应用程序内存泄漏【转】
Java虚拟机性能管理神器 - VisualVM(6) 排查JAVA应用程序内存泄漏[转] 标签: javajvm内存泄漏监控工具 2015-03-11 18:30 1870人阅读 评论(0) 收藏 ...
- C++程序内存泄漏检测方法
一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...
- windbg分析net程序内存泄漏问题
1 问题简介 有客户反馈,打了最新补丁后,服务器的内存暴涨,一直降不下来,程序非常卡.在客户的服务器上抓了一个dump文件,开始分析. 分析问题的思路: 1.找到是那些资源占用了大量内存? ...
- 【转】Unix下C程序内存泄漏检测工具Valgrind安装与使用
Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Goo ...
- Java内存泄漏解析!
前言: 内存管理是Java最重要的优势之一,你只需创建对象,Java垃圾收集器会自动负责分配和释放内存.但是,情况并不那么简单,因为在Java应用程序中经常发生内存泄漏. 本章会说明什么是内存泄漏,为 ...
- WPF应用程序内存泄漏的一些原因
原文:Finding Memory Leaks in WPF-based applications There are numbers of blogs that folks wrote about ...
- 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye
一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...
- 使用WinDug工具调试c#程序或c++程序的dmp崩溃文件,调试内存泄漏
1.调试c#程序内存泄漏步骤 设置symbol符号路径: SRV*c:\mysymbol* http://msdl.microsoft.com/download/symbols;d:/你的pdb文件路 ...
随机推荐
- 解决windwos系统80端口被暂用无法发布(NGINX、TOMCAT、IIS)
原因: 一个操作系统有0-65535个端口,但是一个端口只能被一个应用程序使用.所以80端口只有一个,当开发发布时想用应用NGINX,TOMCAT,IIS发布时,如果有程序占用了,就无法使用了. 解决 ...
- 百度webuploader_c#实现文件分片上传思路
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 如何使用GraphQL Client: Apollo Android
如何使用GraphQL Client: Apollo Android 一个Android app, 如何使用GraphQL. 本文以最流行的Apollo Android为例来说明. 添加依赖 首先, ...
- Spark和Spring整合处理离线数据
如果你比较熟悉JavaWeb应用开发,那么对Spring框架一定不陌生,并且JavaWeb通常是基于SSM搭起的架构,主要用Java语言开发.但是开发Spark程序,Scala语言往往必不可少. 众所 ...
- Mybatis注解开发之@CacheNamespace:实现注解二级缓存的使用
MyBatis二级缓存使用: 官方建议在service使用缓存,但是你也可以直接在mapper层缓存,这里的二级缓存就是直接在Mapper层进行缓存操作 Mybatis的二级缓存实现也十分简单,只要在 ...
- 你们一般都是怎么进行SQL调优的?MySQL在执行时是如何选择索引的?
前言 过年回来的第二周了,终于有时间继续总结知识了.这次来看一下SQL调优的知识,这类问题基本上面试的时候都会被问到,无论你的岗位是后端,运维,测试等等. 像本文标题中的两个问题,就是我在实际面试过程 ...
- Azure Synapse Analytics Serverless
数据湖仓 自从Databricks提出Lakehouse后,同时Snowflake的上市,湖仓一体成为数据领域最火热的话题. https://databricks.com/blog/2020/01/3 ...
- Zeebe服务学习2-状态机
1.什么是状态机? 第一次接触到这个名词,感觉自己是明白这个东东是啥的,但是后来发现,emm-,是的,只是理解了这个词而已. 贴一下官方介绍: 有限状态机,(英语:Finite-state machi ...
- POJ-3259(最短路+Bellman-Ford算法判负圈)
Wormholes POJ-3259 这题是最短路问题中判断是否存在负圈的模板题. 判断负圈的一个关键就是理解:如果在图中不存在从s可达的负圈,最短路径不会经过一个顶点两次.while循环最多执行v- ...
- 从客流统计到营销赋能,Re-ID加速实体商业数字化转型 | 爱分析洞见
2020年中国实体商业受到突发疫情的重大影响.以危机为契机,实体商业加速数字化转型,利用创新应用服务自身业务.在此阶段,基于Re-ID(Person Re-identification,即行人再识别) ...