author:NSX
header-img:img/post-bg-ios9-web.jpg
catalog:true
tags:
-显存占用
--Linux
-killed
近来在CentOS上运行自己写的程序,程序运行时间久一点就被killedlinux查看程序占用内存,须要剖析缘由并找到解决方式.
首先可能缘由是:
显存不够程序出错显存不够问题
查看linux系统日志.
vi /var/log/messages
若果出现kernel:Outofmemory:Killprocess意味着整个系统的显存早已不足,倘若不杀害进程的话,还会造成系统的崩溃.
用free命令查看虚拟显存
free -h
查看某个进程的显存使用情况,使用top命令
top -p `pidof rviz`
top -p id
top -u username
出现如下情况
监控系统报案生产服务进程出现,显存使用率达到90%以上
python程序在长时间(较大负载)运行一段时间后,python进程的系统占用显存持续下降:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14781 root 20 0 10.3g 2.2g 7124 S 0.0 14.5 4:57.13 java
17522 lhadmin 20 0 5915228 1.7g 87264 S 0.0 10.6 1:37.36 python3
# ~~~~~~
# 1.7g 内存占用
这儿的python进程在经历大量恳求处理过程中,显存持续下降,直到最终被killed.
核实过程
明天有7个record没有返回数据的情况,查日志均是ASR/Slottimeout的诱因引起。推测是线程之间发生死锁,gc不能回收linux开发培训,致使多个线程全部挂起,致使显存仍然在下降以及record服务超时!
具体核实过程如下:
top查看CPU和显存占用
# top
strace查看系统调用
# strace -p 6325
ltrace查看库函数调用
# ltrace -cp 6325
gcore生成coredump文件
为了防止gdbattach进程引起的其他影响(例如可能出现进程异常退出,死锁忽然恢复,影响线上服务等),最好将进程生成一个coredump文件,之后再渐渐剖析。
# gcore 6325
# ls -lsh core.6325
2.7G -rw-r--r-- 1 root root 2.7G 4月 14 00:56 core.6325
gdb剖析coredump文件
定位异常:确定python在做哪些,是否有大显存消耗任务正在运行,或出现死锁等异常行为
接入gdb
# gdb python core.6325
# gdb python2.7 core.6325
$ gdb python
使用infothreads查看当前进程的线程列表,发觉大部份都在wait讯号,只有25号线程在做其他事情,切换到25号线程linux计划任务,剖析调用栈:
(gdb) info threads
Id Target Id Frame
18 Thread 0x7f561ae6b740 (LWP 9363) 0x00007f561a76520d in poll () at ../sysdeps/unix/syscall-template.S:81
17 Thread 0x7f5589b17780 (LWP 9463) pthread_cond_wait@@GLIBC_2.3.2 ()
at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
...
一般加锁、死锁情况存在时,会有线程卡在xx_wait等函数上。
...
如果发现某线程有问题,切换到此线程上
...
(gdb) thread 25
查看线程栈信息,
(gdb) info stack
infostack,这个命令只能查看当前正在运行的某个线程的栈信息
使用原始bt来剖析(添加full参数可以看更详尽的内容):
(gdb) bt full
(gdb) thread apply all bt # gdb会让所有线程都执行这个命令
剖析Frame#7发觉当前线程正在执行./service/recall/newuser.py,line49,inget_gametype_anchor_by_sn方式。
找到对应的源代码。通过仔细剖析代码,发觉在某种情况下确实会出现死循环情况,至此问题解决。
死锁解决办法:尝试用锁加以隔离取消多线程自动释放显存:对大的变量储存对象,在使用完成后先del掉,之后在return之前,统一gc.collect()垃圾回收一下总结遇见线上问题时,优先使用gcorePID来保存现场再使用strace、ltrace和gdb剖析假如没有哪些线索linux查看程序占用内存,可以尝试pyrasite-shell或lptracegdb调试Python进程的时侯,运行进程的Python版本和python-dbg一定要匹配参考
核实微服务死循环造成CPU100%问题
Python进程显存下降解决方案
附表:gdb&tracemalloc
python本身是有垃圾回收的,但python有如下几种情况可能出现显存泄漏(即引起对象难以被回收):
循环引用循环引用的链上某个对象定义了__del__方式.对象仍然被全局变量所引用,全局变量生命周期长.垃圾回收机被禁用或则设置成debug状态,垃圾回收的显存不会被释放.引用对象未释放(数据库联接等)
gdb安装教程
详尽信息可以参考debug-with-gdb
touch /etc/yum.repos.d/CentOS-Debuginfo.repo
vi /etc/yum.repos.d/CentOS-Debuginfo.repo
添加以下内容至文件中:
# CentOS-Debug.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# All debug packages from all the various CentOS-5 releases
# are merged into a single repo, split by BaseArch
#
# Note: packages in the debuginfo repo are currently not signed
#
[debug]
name=CentOS-7 - Debuginfo
baseurl=http://debuginfo.centos.org/7/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7
enabled=1
安装依赖
sudo yum install yum-utils
sudo debuginfo-install glibc
sudo yum install gdb python-debuginfo
完成!
查看python显存泄漏的工具
import tracemalloc
tracemalloc.start()
# ... run your application ...
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
print("[ Top 10 ]")
for stat in top_stats[:10]:
print(stat)
snapshot1=tracemalloc.take_snapshot()
…callthefunctionleakingmemory…
snapshot2=tracemalloc.take_snapshot()
top_stats=pare_to(snapshot1,‘lineno’)
print(“[Top10differences]”)forstatintop_stats[:10]:print(stat)
- 显示最大内存块的回溯的代码:
importtracemalloc
Store25frames
tracemalloc.start(25)
…runyourapplication…
snapshot=tracemalloc.take_snapshot()top_stats=snapshot.statistics(‘traceback’)
pickthebiggestmemoryblock
stat=top_stats[0]print(“%smemoryblocks:%.1fKiB”%(stat.count,stat.size/1024))forlineinstat.traceback.format():print(line)“`