Linux中如何获得进程的运行时堆栈

news2024/11/30 10:42:46

关于这个话题,我们一般是为了处理一下生产环境中程序出现死循环或者死锁等问题。我们一般想到的方法就是gdb attach上一个运行中的进程。但是这个需要手动交互。通过网上查找和实践,可以有以下几种选择:

  • 第一种:pstack 进程ID    (pstack就是一个利用gdb实现的shell脚本)
  • 第二种:gcore 进程IP    (gcore也是一个gdb实现的脚本)
  • (看来目前现成的工具都是站在gdb的肩膀上了,除非我们利用ptrace()API参考gdb的源码自己写一个)
  • 第三种:利用fork()的方式,继承一个进程,然后再新的子进程里面直接使用异常信号产生coredump。
描述优点/缺点
pstack依赖系统中的gdb,会是程序短暂的停止运行。

优点:不需要对原有程序做任何改变,直接可以产看运行时。

缺点: 依赖gdb

gcore依赖系统中的gdb,会是程序短暂的停止运行。

优点:不需要对原有程序做任何改变,直接可以产看运行时。

缺点: 依赖gdb

fork()需要改造原有程序,增加事件代码触发fork()动作

优点:不依赖gdb。

缺点: 需要修改源程序

相关代码:

  1. pstack

[root@localhost ~]# cat /usr/bin/gstack
       #!/bin/sh
 
        if test $# -ne 1; then
       
            echo "Usage: `basename $0 .sh` <process-id>" 1>&2
       
            exit 1
        fi
       
        if test ! -r /proc/$1; then
            echo   "Process $1 not found."   1>&2
            exit 1
        fi
       

        # GDB doesn't allow "thread apply all bt" when the process isn't
        # threaded; need to peek at the process to determine if that or the
        # simpler "bt" should be used.
       
        backtrace="bt"
        if test -d /proc/$1/task ; then
            # Newer kernel; has a task/ directory.
            if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then
               backtrace="thread apply all bt"
            fi
        elif test -f /proc/$1/maps ; then
            # Older kernel; go by it loading libpthread.
            if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then
               backtrace="thread apply all bt"
            fi
        fi
        GDB=${GDB:-/usr/bin/gdb}
        if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then
            readnever=--readnever
        else
            readnever=    
        fi
       
        # Run GDB, strip out unwanted noise.
        $GDB --quiet $readnever -nx /proc/$1/exe $1 <<EOF 2>&1 |
        $backtrace
        EOF
         /bin/sed -n \       
         -e  's/^(gdb) //'  \     
         -e  '/^#/p'        \
         -e  '/^Thread/p'       

  [root@localhost ~]#

2. gcore

root@xxx:/App/Log# cat /usr/bin/gcore
#!/bin/sh

#   Copyright (C) 2003-2016 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#
# Script to generate a core file of a running program.
# It starts up gdb, attaches to the given PID and invokes the gcore command.
#

if [ "$#" -eq "0" ]
then
    echo "usage:  $0 [-o filename] pid"
    exit 2
fi

# Need to check for -o option, but set default basename to "core".
name_tail=`date +"%Y-%m-%d-%H.%M.%S"`
tmp_name=gcore-"$name_tail"


name=gcore-"$name_tail"

if [ "$1" = "-o" ]
then
    if [ "$#" -lt "3" ]
    then
        # Not enough arguments.
        echo "usage:  gcore [-o filename] pid"
        exit 2
    fi
    name=$2

    # Shift over to start of pid list
    shift; shift
fi

echo "tmpfile:$tmp_name, outfile:$name"

# Attempt to fetch the absolute path to the gcore script that was
# called.
#binary_path=`dirname "$0"`
binary_path="/usr/bin"

if test "x$binary_path" = x. ; then
  # We got "." back as a path.  This means the user executed
  # the gcore script locally (i.e. ./gcore) or called the
  # script via a shell interpreter (i.e. sh gcore).
  binary_basename=`basename "$0"`

  # If the gcore script was called like "sh gcore" and the script
  # lives in the current directory, "which" will not give us "gcore".
  # So first we check if the script is in the current directory
  # before using the output of "which".
  if test -f "$binary_basename" ; then
    # We have a local gcore script in ".".  This covers the case of
    # doing "./gcore" or "sh gcore".
    binary_path="."
  else
    # The gcore script was not found in ".", which means the script
    # was called from somewhere else in $PATH by "sh gcore".
    # Extract the correct path now.
    binary_path_from_env=`which "$0"`
    binary_path=`dirname "$binary_path_from_env"`
  fi
fi

# Check if the GDB binary is in the expected path.  If not, just
# quit with a message.
if [ ! -f "$binary_path"/gdb ]; then
  echo "gcore: GDB binary (${binary_path}/gdb) not found"
  exit 1
fi

# Initialise return code.
rc=0
echo "---------------------------"
# Loop through pids
for pid in $*
do
        # `</dev/null' to avoid touching interactive terminal if it is
        # available but not accessible as GDB would get stopped on SIGTTIN.
    date
        $binary_path/gdb </dev/null --nx --batch \
            -ex "set pagination off" -ex "set height 0" -ex "set width 0" \
            -ex "attach $pid" -ex "gcore /tmp/$tmp_name.$pid" -ex detach -ex quit

        if [ -r "/tmp/$tmp_name.$pid" ] ; then
            rc=0
        echo "------------------"
        date
        tar -czvPf $name.$pid.tar.gz  "/tmp/$tmp_name.$pid"
        echo "------------------"
        date
        echo "------------------"
        rm -rf "/tmp/$tmp_name.$pid"
        date
        else
            echo "gcore: failed to create $name.$pid"
            rc=1
            break
        fi


done
echo "------------------"
exit $rc

Note: 我们可以一些参数控制gcore参数的coredump文件的大小

3. 使用fork()  (代码略)

参考:

如何获取运行时进程堆栈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/41205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【电商】管理后台--采购管理(执行层)

采购&#xff0c;从表面上看是公司花钱的部门&#xff0c;实则担负了寻找、管理供应商的重任&#xff0c;确保公司绝大部分的供应链成本可以保质、保量的完成。 现在很多电商企业&#xff0c;都不自己生产产品&#xff0c;产品的来源基本上都是从供应商那里采购&#xff0c;所以…

【服务器搭建】教程四:域名怎样进行备案?快来看~

前言 购买一台服务器&#xff0c;再来个域名&#xff0c;搭建一个自己的个人博客网站&#xff0c;把一些教程、源码、想要分享的好玩的放到网站上&#xff0c;供小伙伴学习玩耍使用。我把这个过程记录下来&#xff0c;想要尝试的小伙伴&#xff0c;可以按照步骤&#xff0c;自己…

你好,法语!A2知识点总结(1)

1.语式及时态 语式&#xff1a; 1.1直陈式&#xff1a; -直陈式现在时 1&#xff09;动词变位&#xff1a; 以er结尾的动词为第一组动词 变位规则&#xff1a; 去er&#xff0c;得到词根&#xff0c;加上相应词尾 e es e ons ez ent 第二组动词变位 以ir结尾为第二组动词…

LeetCode 图解 | 141.环形链表

141.环形链表题目描述思路分析快慢指针思想代码实现题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内…

Nuxt 3.0.0正式发布,集成Element Plus和Ant Design Vue脚手架

发布说明 Nuxt 是使用简便的 Web 框架&#xff0c;用于构建现代和高性能的 Web 应用&#xff0c;可以部署在任何运行 JavaScript 的平台上。 Nuxt 3.0 11天前正式发布了稳定版&#xff0c;3.0 基于 Vue 3&#xff0c;为 TypeScript 提供了 “一等公民” 支持&#xff0c;并进行…

【Unity3D】卷轴特效

1 原理 当一个圆在地面上沿直线匀速滚动时&#xff0c;圆上固定点的运动轨迹称为旋轮线&#xff08;或摆线、圆滚线&#xff09;。本文实现的卷轴特效使用了旋轮线相关理论。 以下是卷轴特效原理及公式推导&#xff0c;将屏幕坐标 (x) 映射到纹理坐标 (u)。 注意&#xff1a;屏…

Controller Area Network(CAN)简介

文章目录前言-什么是通讯&#xff1f;一、CAN是什么&#xff1f;二、CAN的应用示例CAN网络细分三、CAN发展历史四、汽车网络汇总总结前言-什么是通讯&#xff1f; “通讯是两个或两个以上参与者之间交换信息的有意识活动&#xff0c;目的是通过符号和语义规范的共享系统来发送…

微服务系列之初探“微服务架构”

随笔 有时你必须对你想得到的东西充满敬畏。 参考书籍&#xff1a; “凤凰架构”“微服务架构设计模式” 在了解微服务架构之前我们有必要解答“什么是架构”、“什么是架构的风格”这两个问题&#xff0c;同时需要带着“架构并不是被发明出来的&#xff0c;而是持续演进的…

[AI] LRTA*ls(k)搜索算法

LRTA*LS[K]一、LRTA*(K)算法的缺点二、LRTA∗LS(k)LRTA*_{LS}(k)LRTA∗LS​(k)算法1、选择局部空间2、更新局部空间论文在这里&#xff01; 一、LRTA*(K)算法的缺点 LRTA*(K)算法每次要更新队列Q里的state&#xff0c;但有三点缺陷&#xff1a; 如果state y进入 Q&#xff0c…

【网络工程】6、防火墙介绍及配置实操

接上篇《5、路由器介绍及配置实操》 之前我们讲解了网络设备路由器的介绍&#xff0c;以及完成了路由器的相关配置实操。本篇我们来讲解防火墙的基础知识以及相应的实操案例。 一、什么是防火墙&#xff1f; 防火墙是一个安全产品&#xff0c;它可以把安全的内网和不安全的外网…

【前端】jQuery-概述+基本使用+常用API

目录 一、jQuery概述 1.1JavaScript库 1.2jQuery的概念 二、jQuery的基本使用 2.1jQuery的下载 2.2jQuery的使用步骤 2.3jQuery的入口函数 2.4jQuery的顶级对象$ 2.5jQuery对象和DOM对象 三、jQuery常用API 3.1jQuery选择器 3.1.1jQuery基础选择器 3.1.2jQuery层级选…

Linux下C语言实现HTTP文件服务器和TCP协议实现网络数据传输

在实际开发中经常用到web框架&#xff0c;比如Servlet&#xff0c;SpringBoot等&#xff0c;这些开发框架提高了我们的开发效率&#xff0c;节省了开发时间。但是这会令我们技术人员处于浮云之上&#xff0c;看不到其本质。说实话&#xff0c;Java语言那么流行&#xff0c;其本…

springboot-自动配置

一、简介 在搭建springboot应用的时候&#xff0c;无需像之前spring的时候&#xff0c;要一堆繁琐的配置文件之类的。一个main的方法&#xff0c;就能把springboot的项目run起来。和其他框架整合也是非常的简单&#xff0c;只需要使用到Enablexxxxx注解就可以搞起来。 二、原理…

外卖项目09---Redis了解

目录 Redis了解 141 一、Redis入门 143 1.1Redis简介 143 1.2Redis下载与安装 143 1.3Redis入门---Redis服务启动 144 1.3.1Redis服务启动 1.3.2设置密码远程连接 二、Redis数据类型 145 三、Redis常用命令 146 3.1Redis常用命令---字符串string操纵命令 3.2Redis…

现代密码学导论-21-分组密码

目录 3.6.3分组密码及其操作模式 ECB(Electronic Code Book) 电码本模式 CBC(Cipher Block Mode) 密文分组链接方式 THEOREM 3.32 CBC模式的CPA安全 连锁CBC模式 OFB(Output Feedback Mode) 输出反馈模式 CTR(Counter) 计数器模式 THEOREM 3.33 CTR多明文PCA安全 THE…

C语言学习之路(基础篇)—— 复合类型(自定义类型)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 结构体 1) 概述 数组&#xff1a;描述一组具有相同类型数据的有序集合&#xff0c;用于处理大量相同类型的数据运算。 结构体&#xff1a;将多个…

工具分享:Springboot+Netty+Xterm搭建一个网页版的SSH终端

一. 简述 搭建一个web ssh&#xff0c;主要是借助websocket和xterm&#xff0c;可以实现一个类似于xshell的效果&#xff0c;如图&#xff1a; 二. 技术栈 这里使用了springboot、netty、jsch、react、Ts,xterm。 这里我用了springboot和netty实现了websocket&#xff0c;js…

稳了,我用 Python 可视化分析和预测了 2022 年 FIFA 世界杯

许多人称足球为 “不可预测的游戏”&#xff0c;因为一场足球比赛有太多不同的因素可以改变最后的比分。 预测一场比赛的最终比分或赢家确实是很难的&#xff0c;但在预测一项比赛的赢家时就不是这样了。在过去的5年中&#xff0c;Bayern Munich 赢得了所有的德甲联赛&#xf…

如何发布一个属于自己的 npm 包

如何发布一个属于自己的 npm 包 start 在日常的工作中&#xff0c;我们会接触很多 npm 包。 例如&#xff1a; npm install jquerynpm install vue/clinpm install axios# ... 等等有时候会想到&#xff0c;构建一个属于自己的 npm 包&#xff0c;应该超级酷吧&#xff1f; …

zabbix基础环境部署

目录 一、环境准备 二、部署LNMP 1、安装Nginx及其依赖包 2、修改nginx配置 3、测试页面 三、部署zabbix服务端 1、下载zabbix 2、安装源码zabbix 3、为zabbix创建数据库与数据库账户 4、搭建Zabbix页面 4.1、第1步 Check of pre-requisites 4.2、第2步 Configure D…