.Net Core在Linux环境dump分析
前言
在本地开发调试的时候,基于VS的工具能方便看出内存泄露的信息:
但到了线上,一般都是在linux环境中,并且服务运行在docker上,这时出现内存泄露,CPU异常等情况,就无法直接调试,只能把docker中在允许的服务内存下来dump信息,进行分析,思路上就这几步:
- 把运行时的内存给dump下来,传到本地
- 能正确读取出dump信息
- 分析原因
1. 生成dump文件
生成dump文件,依赖createdump工具,这个工具是.net core runtime自带的,所以只要运行在.net core上的项目, 就可以直接使用该工具。
- 进行容器内部,dockername 可以通过docker ps得到
docker exec -it dockername /bin/bash
- 找到工具对应的目录:
find /usr/share -name createdump
- 通过上面的路径执行createdump,就会保存当前容器在运行时的信息。
1代表容器内要保存的服务进程号, 如果只是1个服务,默认一般默认为1,最终得到一个createdump.1的文件
/usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.0/createdump 1
如果出现以下信息:
Writing minidump with heap to file /tmp/coredump.1
ptrace(ATTACH, 1) FAILED Operation not permitted
说明没有权限,需要在docker run的时候带上命令 --privileged=true 获取到root权限。
- 从容器中移出, 并放到自己希望的位置上。
docker cp dockername:/tmp/coredump.1 ./
2. 读取dump文件的三个方式
现在已经有了coredump.1,要想办法读取coredump.1进行下一步的分析。
方案有多种,但是最终都是通过sos命令来查看dump信息。
有以下三条路线:
通过windbg+sos读取
读取dump时需所处环境:windows
这块没有尝试,理论上似乎可以。虽然windbg是只能在windows上运行,但结合sos应该可以在windows中读取dump。
dotnet自带的dotnet-dump进行读取
测试读取dump时需所处环境:linux
这个工具的好处,相比下面lldb+sos的方案,安装方便, 官方文档说明点此。
- 安装dotnet-dump
dotnet tool install -g dotnet-dump
设置路径, 结合实际dotnet所在目录
export PATH=$PATH:xxx/.dotnet/tools
export DOTNET_ROOT="xxx/dotnet"
- 载入dump文件
dotnet-dump analyze coredump.1
进入后,执行clrthreads,就会列出当时正在运行的托管线程。
clrthreads
如果无法得到预期结果,出现了:
Failed to load data access module, 0x80004005
Can not load or initialize libmscordaccore.so. The target runtime may not be initialized.
说明必须依赖libmscordaccore.so,但是没有被加载。可惜dotnet-dump工具还不支持单独setclrpath功能,无法载入这个so文件。
通过github看3.1.57502之后的版本应该能支持单独setclrpath了, 因为代码已经改了。
使用lldb+sos读取(推荐)
测试读取dump时需所处环境:Ubuntu
为什么是Ubuntu?因为lldb版本在Ubuntu环境下安装会比较简单。
- 安装lldb
分析.net core2.1及以上的需要装lldb-3.9,2.1之前的需要装3.6版本了。
apt-get update && apt-get install -y \
cmake llvm-3.9 \
clang-3.9 \
lldb-3.9 \
liblldb-3.9-dev \
libunwind8 \
libunwind8-dev \
gettext \
libicu-dev \
liblttng-ust-dev \
libcurl4-openssl-dev \
libssl-dev \
uuid-dev \
libnuma-dev \
libkrb5-dev
安装后通过lldb-3.9命令,能进入就代表正常。
2. 确认sos插件可以使用:
进入lldb后,输入soshelp,能看到以下信息确认soshelp可以使用:
如果看不到:
版本是.net core3及之后的新版:退出lldb,安装dotnet-sos后就能显示
版本是.net core3之前的旧版本:在lldb里加载下sos插件,然后再调用下soshelp就能显示了。
plugin load 你的路径/dotnet/shared/Microsoft.NETCore.App/对应版本/libsosplugin.so
- 都安装完了,带上dump文件测试下
lldb-3.9 $(which dotnet) --core 你的dump文件路径/coredump.1
进入到lldb后
如果是.net core3之前的版本,需要:
plugin load 你的路径/dotnet/shared/Microsoft.NETCore.App/对应版本/libsosplugin.so
查看下当前dump文件里的线程,输入sos Threads后就能看到:
比如想看ID 11的线程详情,可以先setsostid 14 11锁定线程:
然后再sos ClrStack查看线程内部信息
如果sos Threads后无法得到预期结果,出现了:
Failed to load data access module, 0x80004005
Can not load or initialize libmscordaccore.so. The target runtime may not be initialized.
说明必须依赖libmscordaccore.so,执行setclrpath:
setclrpath 你的路径/dotnet/shared/Microsoft.NETCore.App/对应的.net core版本
3.分析
我们已经能通过sos的命令显示出堆栈信息,通过这些信息就可以进行分析。
首先一定要熟悉sos里面的每个命令,因为上面不管哪种读取dump方式,其实最终都是依靠sos插件。
然后根据遇到的不同情况再做不同角度的分析, 这里顺便连接一些通用的分析方法:
内存使用过多的情况分析
CPU过高的情况分析
更多推荐
所有评论(0)