远程debug调试java代码

日常环境和预发环境遇到问题时,可以用远程调试的方法本地打断点,在本地调试。生产环境由于网络隔离和系统稳定性考虑,不能进行远程代码调试。

 

整体过程是通过修改远程服务JAVA_OPTS参数,然后本地通过Eclipse或IDEA等工具调试。

下面简单介绍下理论。
远程调试
远程调试分为主动连接调试,和被动连接调试。这里以Eclipse为例。

主动连接调试:服务端配置监控端口,本地IDE连接远程监听端口进行调试,一般调试问题用这种方式。

被动连接调试:本地IDE监听某端口,等待远程连接本地端口。一般用于远程服务启动不了,启动时连接到本地调试分析。
主动连接调试
首先需要远程服务配置启动脚本:

JAVA_OPTS="$JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000"
如果是启动jar包,指令:

java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -jar test.jar  
这里-Xdebug是通知JVM工作在DEBUG模式下,-Xrunjdwp是通知JVM使用(java debug wire protocol)来运行调试环境。transport是监听Socket端口连接方式(也可以dt_shmem共享内存方式,但限于windows机器,并且服务提供端和调试端只能位于同一台机)。server=y表示当前是调试服务端,=n表示当前是调试客户端。suspend=n表示启动时不中断(如果启动时中断,一般用于调试启动不了的问题)。address=8000表示本地监听8000端口。

远程服务(tomcat/jboss)启动成功后,本地Eclipse/idea对需要调试的地方打上断点,然后项目右键启动远程调试:Debug as->Debug Configurations->Remote Java Application。Host为远程主机IP,Port为远程监听调试端口,Connection Type为:Standard(Socket Attach),如图:远程服务器地址为172.10.12.32 监听端口为5005  服务器中启动参数配置为:

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

start.sh:

#!/bin/bash
source $(readlink -f $(dirname $0))/../../env.sh
PID_HOME=server.pid
LOG_DIR=${artifactId}
if [ ! -d "$PID_HOME" ]; then
   touch $PID_HOME
fi
if [ ! -d "$LOG_DIR" ]; then
   mkdir $LOG_DIR
fi
nohup java -server $(jvm.param) -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=1 -XX:SurvivorRatio=4 -XX:CMSInitiatingOccupancyFraction=70 -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+HeapDumpOnOutOfMemoryError -Xloggc:logs/$1_gc.log -Xloggc:logs/$1_gc.log -jar ./lib/${artifactId}-${version}.jar>/dev/null 2>&1&
echo $! > $PID_HOME

debugStart.sh:

java -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9989,server=y,suspend=n  -jar bot-center-core-1.0.0-SNAPSHOT.jar

stop.sh:

#!/bin/sh
get_pid() {
    STR=$1
    PID=$2
        if [ ! -z "$PID" ]; then
            JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep "$PID"|grep -v grep|awk '{print $2}'`
        else
            JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep -v grep|awk '{print $2}'`
        fi
    echo $JAVA_PID;
}

base=`dirname $0`/..

appName=${artifactId}-${version}

pid=""

if [ "$pid" == "" ] ; then
    pid=`get_pid "${appName}"`
fi

if [ "$pid" == "" ]; then
    echo "${appName} is not running."
    exit -1;
fi

echo -e "`hostname`: stopping ${appName} $pid ... "
kill -15 $pid

LOOPS=0
while (true);
do
    gpid=`get_pid "appName=${appName}" "$pid"`
    if [ "$gpid" == "" ] ; then
        echo "Oook! cost:$LOOPS"
        if [ -f "$pidfile" ]; then
                `rm $pidfile`
        fi
        break;
    fi
    let LOOPS=LOOPS+1
    sleep 1
done

补充:后台启动程序nohup

在刚开始部署及测试SpringBoot打包的jar包时,常会将jar包抛到服务器上,直接运行 java -jar 命令来启动。但这样的话,该会话的终端窗口如果中断,程序也会挂掉,所以我们会采用nohup和&组合命令来操作。

使用nohup运行程序:

  • 结果默认会输出到nohup.out
  • 使用Ctrl + C发送SIGINT信号,程序关闭
  • 关闭session发送SIGHUP信号,程序免疫

使用&后台运行程序:

  • 结果会输出到终端
  • 使用Ctrl + C发送SIGINT信号,程序免疫
  • 关闭session发送SIGHUP信号,程序关闭
nohup java -jar app.jar &

这种方式启动项目会默认生成一个nohup.out的文件来记录日志,而且这个文件太占磁盘空间,所以为了减少磁盘被大量消耗,设置启动项目时不输出nohup.out文件。

可以采用如下两种方式:

# 把标准输出重定向到空设备,即只输出错误信息到日志文件
nohup java -jar app.jar >/dev/null 2>log & 
# 把标准输出和标准错误全重定向到空设备,即不输出日志
nohup java -jar app.jar >/dev/null 2>&1 & 

两个shell语法的解释:

1.   >/dev/null

这条命令的作用是将标准输出1重定向到/dev/null中。 /dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。那么执行了>/dev/null之后,标准输出就会不再存在,没有任何地方能够找到输出的内容。

2.   2>&1

这条命令用到了重定向绑定,采用&可以将两个输出绑定在一起。这条命令的作用是错误输出将和标准输出同用一个文件描述符,说人话就是错误输出将会和标准输出输出到同一个地方。

linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令,所以>/dev/null 2>&1的作用就是让标准输出重定向到/dev/null中(丢弃标准输出),然后错误输出由于重用了标准输出的描述符,所以错误输出也被定向到了/dev/null中,错误输出同样也被丢弃了。执行了这条命令之后,该条shell命令将不会输出任何信息到控制台,也不会有任何信息输出到文件中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值