记一次 .NET某游戏币自助机后端 内存暴涨分析
一:背景
1. 讲故事
前些天有位朋友找到我,说他们的程序内存会偶发性暴涨,自己分析了下是非托管内存问题,让我帮忙看下怎么回事?哈哈,看到这个dump我还是非常有兴趣的,居然还有这种游戏币自助机类型的程序,下次去大玩家看看他们出币的机器后端是不是C#写的?由于dump是linux上的程序,刚好windbg可以全平台分析,太爽了,直接用windbg开干吧。
二:WinDbg 分析
1. 到底是哪里的泄漏
在 windows 平台上相信有很多朋友都知道用 !address -summary
命令看,但这是专属于windows平台的命令,在分析linux上的dump不好使,参考如下输出:
0:000> !address -summary--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unknown> 1685 7ffc`d6725c00 ( 127.988 TB) 100.00% 100.00%
Image 7102 0`0b524400 ( 181.142 MB) 0.00% 0.00%--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal2248 7ffc`02549000 ( 127.984 TB) 100.00%
MEM_PRIVATE 6539 0`df701000 ( 3.491 GB) 0.00% 0.00%--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal2248 7ffc`02549000 ( 127.984 TB) 100.00% 100.00%
MEM_COMMIT 6539 0`df701000 ( 3.491 GB) 0.00% 0.00%--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 2099 0`dd75e000 ( 3.460 GB) 0.00% 0.00%
PAGE_EXECUTE_WRITECOPY 33 0`00d4c000 ( 13.297 MB) 0.00% 0.00%
PAGE_READONLY 2736 0`00b01000 ( 11.004 MB) 0.00% 0.00%
PAGE_EXECUTE_READ 1671 0`00756000 ( 7.336 MB) 0.00% 0.00%--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
<unknown> 0`00000000 55cb`2dc3b000 ( 85.794 TB)
Image 7f71`9dbdd000 0`01b16000 ( 27.086 MB)
卦中的内存段分类用处不大,也没有多大的参考价值,那怎么办呢?其实 coreclr 团队也考虑到了这个情况,它提供了一个 maddress 命令来实现跨平台的 !address
,更改后输出如下:
0:000> !sos maddress
Enumerating and tagging the entire address space and caching the result...
Subsequent runs of this command should be faster.
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Memory Kind | StartAddr | EndAddr-1 | Size | Type | State | Protect | Image | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Stack | 7f6e356ec000 | 7f6e35eec000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | | | Stack | 7f6e35eed000 | 7f6e366ed000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | | | Stack | 7f6e366ee000 | 7f6e36eee000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | | | Stack | 7f6e36eef000 | 7f6e376ef000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | | ...+-------------------------------------------------------------------------+ | Memory Type | Count | Size | Size (bytes) | +-------------------------------------------------------------------------+ | Stack | 423 | 3.29gb | 3,528,859,648 | | Image | 7,102 | 181.14mb | 189,940,736 | | PAGE_READWRITE | 206 | 89.18mb | 93,511,680 | | GCHeap | 3 | 37.75mb | 39,587,840 | | HighFrequencyHeap | 395 | 24.66mb | 25,858,048 | | LowFrequencyHeap | 316 | 22.20mb | 23,277,568 | | LoaderCodeHeap | 13 | 17.00mb | 17,825,792 | | ResolveHeap | 2 | 732.00kb | 749,568 | | HostCodeHeap | 8 | 668.00kb | 684,032 | | DispatchHeap | 1 | 196.00kb | 200,704 | | PAGE_EXECUTE_WRITECOPY | 6 | 184.00kb | 188,416 | | CacheEntryHeap | 3 | 164.00kb | 167,936 | | IndirectionCellHeap | 3 | 152.00kb | 155,648 | | LookupHeap | 3 | 144.00kb | 147,456 | | StubHeap | 2 | 76.00kb | 77,824 | | PAGE_EXECUTE_READ | 1 | 4.00kb | 4,096 | +-------------------------------------------------------------------------+ | [TOTAL] | 8,487 | 3.65gb | 3,921,236,992 | +-------------------------------------------------------------------------+
从卦中可以看到当前程序总计 3.65G
内存占用,基本上都被线程栈给吃掉了,更让人意想不到的是这个线程栈居然占用 8M 的内存空间,这个着实有点大了,而且 linux 不像 windows 有一个 reserved 的概念,这里的 8M 是实实在在的预占,可以观察这 8M 的内存地址即可,都是初始化的 0, 这就说不过去了。
0:000> dp 7f6e356ec000 7f6e35eec000
00007f6e`356ec000 00000000`00000000 00000000`00000000
...
00007f6e`35eebfc0 00000000`00000000 00000000`00000000
00007f6e`35eebfd0 00000000`00000000 00000000`00000000
00007f6e`35eebfe0 00000000`00000000 00000000`00000000
00007f6e`35eebff0 00000000`00000000 00000000`00000000
2. 如何修改栈空间大小
一般来说不同的操作系统发行版有不同的默认栈空间配置,可以先到内存搜一下当前是哪一个发行版,做法就是搜索操作系统名称主要关键字。
0:000> s-a 0 L?0xffffffffffffffff "centos"
...
000055cb`2ecf08c8 63 65 6e 74 6f 73 2e 37-2d 78 36 34 00 00 00 00 centos.7-x64....
...
从卦中可以看到当前操作系统是 centos7-x64
,在 windows 平台上修改栈空间大小可以修改 PE 头,在 linux 上有两种做法。
- 修改 ulimit -s 参数
root@ubuntu:/data# ulimit -s
8192
root@ubuntu:/data# ulimit -s 2048
root@ubuntu:/data# ulimit -s
2048
- 修改 DOTNET_DefaultStackSize 环境变量
DOTNET_DefaultStackSize=180000
更多可以参考文章: https://www.alexander-koepke.de/post/2023-10-18-til-dotnet-stack-size/
上面是解决问题的第一个方向,接下来我们说另一个方向,为什么会产生总计 423 个线程呢?
3. 为什么会有那么多线程
要找到这个答案,需要去看每一个线程此时都在干嘛,这个可以使用 windbg 专属命令。
0:000> ~*e !clrstack
...
OS Thread Id: 0x4e (24)Child SP IP Call Site
00007F70B20FC4B0 00007f71a4131ad8 [InlinedCallFrame: 00007f70b20fc4b0] /app/Confluent.Kafka.dll!Unknown
00007F70B20FC4B0 00007f7130299970 [InlinedCallFrame: 00007f70b20fc4b0] /app/Confluent.Kafka.dll!Unknown
00007F70B20FC4A0 00007f7130299970 ILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr)
00007F70B20FC530 00007f7130309fab /app/Confluent.Kafka.dll!Unknown
00007F70B20FC880 00007f7131c5a75d /app/Confluent.Kafka.dll!Unknown
00007F70B20FC8A0 00007f7130303ebe /app/DotNetCore.CAP.Kafka.dll!Unknown
00007F70B20FC980 00007f71302f4854 /app/DotNetCore.CAP.dll!Unknown
00007F70B20FCA50 00007f7129b187f4 System.Threading.Tasks.Task.InnerInvoke() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2387]
00007F70B20FCA70 00007f7129b1d316 System.Threading.Tasks.Task+c.<.cctor>b__272_0(System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2375]
00007F70B20FCA80 00007f7129b03d6b System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @ 183]
00007F70B20FCAD0 00007f7129b18524 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2333]
00007F70B20FCB50 00007f7129b18418 System.Threading.Tasks.Task.ExecuteEntryUnsafe(System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2271]
00007F70B20FCB70 00007f7129b21a67 System.Threading.Tasks.ThreadPoolTaskScheduler+c.<.cctor>b__10_0(System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs @ 35]
00007F70B20FCB80 00007f7129af88c2 System.Threading.Thread.StartCallback() [/_/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @ 105]
00007F70B20FCCF0 00007f71a37ab9c7 [DebuggerU2MCatchHandlerFrame: 00007f70b20fccf0]
...
从卦中数据看有很多的 Unknown
,说明dump取得不好,可能不是用正规的 dotnet-dump 或者 procdump,但不管怎么说,还是可以看到大量的和 Kafka 有关的链接库,并且从 InnerInvoke
这个执行 m_action 来看,应该是有大量线程卡在 Kafka 中的某个函数上。
有了这些知识,最后给到朋友的建议如下:
- 修改 DOTNET_DefaultStackSize 参数
可以仿照 windows 上的 .netcore 默认 1.5M 的栈空间设置,因为8M真的太大了,扛不住,也和 Linux 的低内存使用不符。
- 观察 Kafka 的相关逻辑
毕竟有大量线程在 Kafka 的等待上,个人觉得可能是订阅线程太多,或者什么业务执行时间长导致的线程饥饿,尽量把线程压下去。
三:总结
Linux 上的 .NET 调试生态在日渐丰富,这是一件让人很兴奋的事情,最后再给 WinDbg 点个赞,它不仅可以全平台dump分析,还可以实时调试 Linux 进程,现如今的WinDbg真的是神一般的存在。
相关文章:
记一次 .NET某游戏币自助机后端 内存暴涨分析
一:背景 1. 讲故事 前些天有位朋友找到我,说他们的程序内存会偶发性暴涨,自己分析了下是非托管内存问题,让我帮忙看下怎么回事?哈哈,看到这个dump我还是非常有兴趣的,居然还有这种游戏币自助机…...
计算机考研|哪些985/211院校不歧视双非二本生?
说句残酷的话,能对某一专业做出贡献,那么你的水平肯定是很高的。如果普通学生,普通本科的话可能很难做到这一点。这也是现在考研风气比较强的原因,一部分专业能力不突出的学生来选择深造3年。 对于基础较差想要考计算机研究生的同…...
Spring Boot:简化 Java 应用开发的艺术
Spring Boot 是一种用于快速开发、运行和管理 Java 应用程序的开源框架。它简化了基于 Spring 的应用程序的配置和部署,使得开发者能够更加专注于业务逻辑的实现。本文将介绍 Spring Boot 的核心特性、优势以及如何在项目中使用 Spring Boot。 一、核心特性 自动配…...
elasticsearch安装与使用(2)-基于term匹配的简单搜索引擎搭建
把一篇pdf论文解析后,放入es数据库中,建立倒排索引表,并实现简单搜索。 1、pdf论文解析(英文) 安装pdf解析包 pip install pdfminer.sixdef extract_text_from_pdf(filename, page_numbersNone, min_line_length1):从pdf文件中提取文字:pa…...
速盾:ddos防护与高防ip区别?
在网络安全领域,DDOS 防护和高防 IP 都是重要的防护手段,但它们之间存在着一些明显的区别。 DDOS 防护是一种针对分布式拒绝服务攻击的防御策略。它通过多种技术和方法来识别和抵御 DDOS 攻击。常见的 DDOS 防护手段包括流量清洗、连接限制、协议分析等。…...
Java中StringBulider详解
StringBuilder 是 Java 中一个用来创建可变字符串的类。与 String 类不同,StringBuilder 对象能够被修改,不会创建新的对象,因此在需要进行大量字符串操作时,StringBuilder 更高效。以下是 StringBuilder 的详细讲解。 创建 Stri…...
基于springboot高校就业招聘系统的设计
管理员账户功能包括:系统首页,个人中心,就业咨询管理,毕业去向管理,简历管理,管理员管理,基础数据管理 辅导员账户功能包括:系统首页,个人中心,就业咨询管理…...
嵌入式C语言编码规范要点
1.函数命名方法 骆驼命名法(Camel) 帕斯卡命名法((pascal),也叫大驼峰命名法(Upper Camel Case) 匈牙利命名法 下划线命名法(也称为蛇形命名法) 详述见之前文…...
Python中的全局解释器锁:深入解析与应对策略
1. 引言 在Python的世界里,全局解释器锁(GIL)是一个经常被讨论的话题。它既是Python并发编程中的一个重要概念,也是许多开发者感到困惑的源头。本文将深入探讨GIL的工作原理、它对Python程序性能的影响 2. 全局解释器锁的历史背…...
【java计算机毕设】图书商城管理系统MySQL springboot vue html maven送文档
1项目功能介绍 【java计算机毕设】图书商城管理系统 Java Spring Boot vue HTML MySQL 赠送文档 PPT 2项目简介 系统功能: 图书商城管理系统包括管理员和用户两种角色。 管理员的功能包括在个人中心修改个人信息,以及在基础数据管理中管理会员等级类型和…...
【Java刷题】二叉树
相同的树 public boolean isSameTree(TreeNode p, TreeNode q) {if(p null && q null) {return true;} else if(p ! null && q ! null) {if(p.val ! q.val) {return false;} else {return isSameTree(p.left, q.left) && isSameTree(p.right, q.rig…...
【Linux】程序地址空间之动态库的加载
我们先进行一个整体轮廓的了解,随后在深入理解细节。 在动态库加载之前还要说一下程序的加载,因为理解了程序的加载对动态库会有更深的理解。 轮廓: 首先,不管是程序还是动态库刚开始都是在磁盘中的,想要执行对应的可…...
LabVIEW处理大量数据时,怎样确保数据的准确性和完整性?
在LabVIEW处理中,确保大量数据的准确性和完整性至关重要。以下是详细的多角度分析和建议,以确保在LabVIEW中处理大量数据时,数据的准确性和完整性: 1. 数据采集阶段 1.1 高精度硬件选择 选择高精度的数据采集硬件,如…...
容器是什么?
概念 容器可以被看作是一种轻量级的虚拟化技术。与传统虚拟化技术相比,容器不需要为每个应用程序提供单独的操作系统,它们共享宿主机的操作系统内核。这使得容器更加轻便和高效。 想象一下,容器就像是一艘艘可以在海洋中独立航行的货轮&…...
#15 从Stable Diffusion生成的艺术中寻找灵感
文章目录 前言1. Stable Diffusion简介2. 寻找灵感的途径2.1 深入探索主题2.2 结合多种艺术风格2.3 实验不同的创意组合 3. 灵感应用3.1 艺术创作3.2 设计项目3.3 故事讲述 4. 实践建议4.1 记录和迭代4.2 开放实验4.3 结合个人风格 结论 前言 在当今的数字时代,人工…...
git rebase
1. git rebase的意义 首先理解这个rebase,它的意思是re base,翻译过来就是“重新基于”。 意义是:重新整理当前分支的开发线,使其变成基于某个开发节点的开发线。 2. rebase用于并行开发 构造两个分支master和feature…...
Docker引起的漏洞问题
前言 测试环境上的中间件和java应用都是由docker进行部署的,但是因为docker的镜像访问有时候需要外网,由此引发了问题,在docker文件中 /usr/lib/systemd/system/docker.service 原有的配置为,可以看到进行了加密 ExecStart/usr/bin/dockerd --tlsverify --tlscacert/etc/docker…...
Oracle基本数据类型
在Oracle数据库中,数据类型是描述数据存储格式的属性。不同的数据类型允许存储不同种类的数据。以下是Oracle中的一些基本数据类型: 1. 字符数据类型 - CHAR(size): 定长字符数据,最大长度为2000字节。 - VARCHAR2(size): 变长字符数据…...
VS+QT+OCC创建坐标界面
1、安装并配置好项目后,填写如下代码: #pragma once#include <Standard_Handle.hxx> #include <V3d_Viewer.hxx> #include <OpenGl_GraphicDriver.hxx> #include <WNT_Window.hxx> #include <V3d_View.hxx> #include <…...
VUE2.7项目配置webpack打包-详细操作步骤
一、Webpack简介 Webpack是一个打包工具,可以把JS、CSS、Node Module、Coffeescrip、SCSS/LESS、图片等都打包在一起,因此,现在几乎所有的SPA项目、JS项目都会用到Webpack。 官网:https://webpack.js.org GitHub为https://git…...
Linux系统Docker部署Apache Superset并实现远程访问详细流程
目录 前言 1. 使用Docker部署Apache Superset 1.1 第一步安装docker 、docker compose 1.2 克隆superset代码到本地并使用docker compose启动 2. 安装cpolar内网穿透,实现公网访问 3. 设置固定连接公网地址 前言 作者简介: 懒大王敲代码࿰…...
Cochrane Library循证医学数据库的介绍及文献下载
今天要讲的数据库是Cochrane Library循证医学数据库,我们先来了解一下该数据库: Cochrane Library是国际Cochrane Collaboration的主要产品,由英国Wiley InterScience公司出版发行。是一个提供高质量证据的数据库,是循证医学的证…...
冯喜运:6.12今日黄金原油行情还会涨吗?黄金原油独家操作策略
【黄金消息面分析】:据荷兰国际集团(ING)大宗商品策略师埃瓦?曼西(Ewa Manthey)称,黄金价格正面临来自美元走强和中国需求疲软的新阻力,但一旦美联储开始降息,黄金价格将恢复反弹。 【黄金技术面分析】:黄金…...
VM ubuntu终端使用Host代理的方法
1、设置网络地址转换NAT 2、在终端敲击如下命令 先敲击 ip route show 找到网关。再敲击如下命令: export http_proxyhttp://10.0.2.2:33210 export https_proxyhttp://10.0.2.2:33210 export HTTP_PROXYhttp://10.0.2.2:33210/ export HTTPS_PROXYhttp://10.0.2.…...
【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 破译犯罪时间(100分) - 三语言AC题解(Python/Java/Cpp)
🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 破译犯罪时间(100分) 🌍 评测功能需要订阅专栏后私信联系清…...
大模型学习之GLM结构
探索GLM:一种新型的通用语言模型预训练方法 随着人工智能技术的不断进步,自然语言处理(NLP)领域也迎来了革命性的发展。OpenAI的ChatGPT及其后续产品在全球范围内引起了广泛关注,展示了大型语言模型(LLM&a…...
C#类库打包支持多个版本的类库
修改csproj <Project Sdk"Microsoft.NET.Sdk"><PropertyGroup><TargetFrameworks>netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks><PackageId>xxxx</PackageId><Version>1.0.0</Version><Author…...
一文介绍暗区突围手游 游戏特色、具体玩法和独特的玩法体验
🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 《暗区突围》是一款由腾讯魔方工作室群开发的第一人称射击游戏,于 2022 年 7 月 13 日正式公测,支持 Android 和 iOS 平台。这款游戏以从虚构的暗区收集物资并安全撤离作为最终目…...
Unity基础(三)3D场景搭建
目录 简介: 一.下载新手资源 二.创建基本地形 三.添加场景细节 四,添加水 五,其他 六. 总结 简介: 在 Unity 中进行 3D 场景搭建是创建富有立体感和真实感的虚拟环境的关键步骤。 首先,需要导入各种 3D 模型资源,如建筑物、角色、道具等。这些模…...
在Spring Boot中使用Sa-Token实现路径拦截和特定接口放行
在Spring Boot中使用Sa-Token实现路径拦截和特定接口放行 很喜欢的一段话:别想太多,好好生活,也许日子过着过着就会有答案,努力走着走着就会有温柔的着落。 春在路上,花在枝上,所有的美好都在路上ÿ…...
网站公告怎么做/山东建站管理系统
Queryable类是C#中的一个泛型类,它提供了一组用于查询数据源的方法。这些方法可以用于对各种数据源进行查询,包括对象集合、数组、XML文档和数据库表。 Queryable类的方法可以用于过滤、排序、分组和投影数据,以及执行聚合操作,如…...
郑州网站建设网站推广/哪个网站做推广效果好
android:resizeableActivity[“true” | “false”] 如果该属性设置为 true,Activity 将能以分屏和自由形状模式启动。 如果此属性设置为 false,Activity 将不支持多窗口模式。 如果该值为 false,且用户尝试在多窗口模式下启动 Activity&…...
公司注册资金实缴新政策出台2024/杭州优化公司多少钱
仲恺农业工程学院工程实训报告ATM取款机课程名称 C 语言程序设计工程实训 姓 名 林少烈院(系) 计算机科学与工程学院专业班级计算机 113 班学 号 4317指导教师 王成仲恺农业工程学院教务处制需求分析 . 错 误 ! 未定义书签。系统总框图和功能模块说明 错 误!未定义书签。系统总…...
h5网站制作一般多少钱/杭州专业seo服务公司
1.创建项目:切换到创建项目的目录,输入 django-admin startproject firstproject firstproject为项目名称,创建成功后会在创建目录的位置创建一个firstproject的文件夹 文件夹中各个文件的功能如下: 创建项目应用APP:…...
goz建站/软文网
下面我们讲解登录功能。首先为了方便我们开发,我们在根目录(www目录)下建立一个项目文件夹,叫joke。接着在joke下建立两个文件夹,一个叫admin后台文件夹,另一个叫home前台文件夹(当然,你也可以使用别的名称,…...
万网做网站花多少钱/优化大师下载安装
在前面提到过,Starling是Sparrow的姊妹篇,正因为这样,Starling里的touch事件的机制其实是为移动设备的触摸交互设计的,所以当你使用它进行使用鼠标交互的桌面应用开发时,第一眼会感觉有些困惑。 首先,如果你…...