author:NSX

header-img:img/post-bg-ios9-web.jpg

catalog:true

tags:

-显存占用

--Linux

-killed

近来在CentOS上运行自己写的程序,程序运行时间久一点就被killedlinux查看程序占用内存,须要剖析缘由并找到解决方式.

首先可能缘由是:

显存不够程序出错显存不够问题

查看linux系统日志.

  1. vi /var/log/messages

若果出现kernel:Outofmemory:Killprocess意味着整个系统的显存早已不足,倘若不杀害进程的话,还会造成系统的崩溃.

用free命令查看虚拟显存

  1. free -h

查看某个进程的显存使用情况,使用top命令

  1. top -p `pidof rviz`
  2. top -p id
  3. top -u username

出现如下情况

监控系统报案生产服务进程出现,显存使用率达到90%以上

python程序在长时间(较大负载)运行一段时间后,python进程的系统占用显存持续下降:

  1. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  2. 14781 root 20 0 10.3g 2.2g 7124 S 0.0 14.5 4:57.13 java
  3. 17522 lhadmin 20 0 5915228 1.7g 87264 S 0.0 10.6 1:37.36 python3
  4. # ~~~~~~
  5. # 1.7g 内存占用

这儿的python进程在经历大量恳求处理过程中,显存持续下降,直到最终被killed.

核实过程

明天有7个record没有返回数据的情况,查日志均是ASR/Slottimeout的诱因引起。推测是线程之间发生死锁,gc不能回收linux开发培训,致使多个线程全部挂起,致使显存仍然在下降以及record服务超时!

具体核实过程如下:

top查看CPU和显存占用

  1. # top

strace查看系统调用

  1. # strace -p 6325

ltrace查看库函数调用

  1. # ltrace -cp 6325

gcore生成coredump文件

为了防止gdbattach进程引起的其他影响(例如可能出现进程异常退出,死锁忽然恢复,影响线上服务等),最好将进程生成一个coredump文件,之后再渐渐剖析。

  1. # gcore 6325
  2. # ls -lsh core.6325
  3. 2.7G -rw-r--r-- 1 root root 2.7G 4 14 00:56 core.6325

gdb剖析coredump文件

定位异常:确定python在做哪些,是否有大显存消耗任务正在运行,或出现死锁等异常行为

接入gdb

  1. # gdb python core.6325
  2. # gdb python2.7 core.6325
  3. $ gdb python

linux查看程序占用内存_linux查看程序占用资源_查看占用内存linux

使用infothreads查看当前进程的线程列表,发觉大部份都在wait讯号,只有25号线程在做其他事情,切换到25号线程linux计划任务,剖析调用栈:

  1. (gdb) info threads
  2. Id Target Id Frame
  3. 18 Thread 0x7f561ae6b740 (LWP 9363) 0x00007f561a76520d in poll () at ../sysdeps/unix/syscall-template.S:81
  4. 17 Thread 0x7f5589b17780 (LWP 9463) pthread_cond_wait@@GLIBC_2.3.2 ()
  5. at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
  6. ...
  7. 一般加锁、死锁情况存在时,会有线程卡在xx_wait等函数上。
  8. ...
  9. 如果发现某线程有问题,切换到此线程上
  10. ...
  11. (gdb) thread 25

查看线程栈信息,

  1. (gdb) info stack

infostack,这个命令只能查看当前正在运行的某个线程的栈信息

使用原始bt来剖析(添加full参数可以看更详尽的内容):

  1. (gdb) bt full
  2. (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

linux查看程序占用内存_查看占用内存linux_linux查看程序占用资源

python本身是有垃圾回收的,但python有如下几种情况可能出现显存泄漏(即引起对象难以被回收):

循环引用循环引用的链上某个对象定义了__del__方式.对象仍然被全局变量所引用,全局变量生命周期长.垃圾回收机被禁用或则设置成debug状态,垃圾回收的显存不会被释放.引用对象未释放(数据库联接等)

gdb安装教程

详尽信息可以参考debug-with-gdb

  1. touch /etc/yum.repos.d/CentOS-Debuginfo.repo
  2. vi /etc/yum.repos.d/CentOS-Debuginfo.repo

添加以下内容至文件中:

  1. # CentOS-Debug.repo
  2. #
  3. # The mirror system uses the connecting IP address of the client and the
  4. # update status of each mirror to pick mirrors that are updated to and
  5. # geographically close to the client. You should use this for CentOS updates
  6. # unless you are manually picking other mirrors.
  7. #
  8. # All debug packages from all the various CentOS-5 releases
  9. # are merged into a single repo, split by BaseArch
  10. #
  11. # Note: packages in the debuginfo repo are currently not signed
  12. #
  13. [debug]
  14. name=CentOS-7 - Debuginfo
  15. baseurl=http://debuginfo.centos.org/7/$basearch/
  16. gpgcheck=1
  17. gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7
  18. enabled=1

安装依赖

  1. sudo yum install yum-utils
  2. sudo debuginfo-install glibc
  3. sudo yum install gdb python-debuginfo

完成!

查看python显存泄漏的工具

  1. import tracemalloc
  2. tracemalloc.start()
  3. # ... run your application ...
  4. snapshot = tracemalloc.take_snapshot()
  5. top_stats = snapshot.statistics('lineno')
  6. print("[ Top 10 ]")
  7. for stat in top_stats[:10]:
  8. print(stat)

snapshot1=tracemalloc.take_snapshot()

…callthefunctionleakingmemory…

snapshot2=tracemalloc.take_snapshot()

top_stats=pare_to(snapshot1,‘lineno’)

print(“[Top10differences]”)forstatintop_stats[:10]:print(stat)

  1. - 显示最大内存块的回溯的代码:

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)“`

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复