《HotSpot实战》—— 1.3 实战:在HotSpot内调试HelloWorld

1.3 实战:在HotSpot内调试HelloWorld

本节讲解的是Java入门程序HelloWorld在HotSpot上的执行过程。我们通过一个普通Java程序的运行过程,能够以点带面地讲解到涉及HotSpot内部实现的基础概念。

虽然是调试简单的HelloWorld程序,但在这个过程中会涉及HotSpot的基本数据结构以及环境准备等内容。理解这些,一方面使读者对HotSpot项目有个感性认识,其实调试HotSpot没有想象的那么困难,这利于我们增强驾驭HotSpot的自信心;另一方面,让我们正式接触到HotSpot的基本代码,并掌握HotSpot项目的基本调试方法。

调试准备过程如图1-6所示,具体步骤如下。

(1)选择调试器。

(2)配置GDB工作目录的绝对路径。

(3)配置JDK和动态链接库路径。

(4)定位Launcher。

(5)运行GDB初始化脚本,准备GDB运行环境。

(6)设置HotSpot项目断点。

(7)启动调试脚本。

(8)虚拟机运行HelloWorld程序,在断点处暂停。

(9)利用GDB命令调试HotSpot虚拟机程序的运行。

接下来,我们先了解一下如何使用GDB调试程序,然后开启我们的调试之旅。

1.3.1 认识GDB

本地程序(C/C++)的调试,一般使用GDB命令。对于Java程序员来说,GDB有些陌生,其实我们只需要掌握一些基本的调试命令,便足够应付HotSpot的调试任务了。

下面附上一些常用的GDB命令,包括断点、执行、查看代码、查看栈帧、查看数据等,如清单1-16所示。

清单1-16
断点:

break InitializeJVM:在InitializeJVM函数入口处设置断点
break java.c:JavaMain:在源文件java.c的InitializeJVM函数入口处设置断点
break os_linux.cpp:4380:在源文件os_linux.cpp的第4380行处设置断点
break *0x8048000:在地址为0x8048000的地址处设置断点
delete 1:删除断点1
delete:删除所有断点
执行:
step:执行1条语句,会进入函数
step n:执行n条语句,会进入函数
next:与step类似,但是不进入函数
next n:与step n类似,但是不进入函数
continue:继续运行
finish:运行至当前函数返回后退出
查看代码:
list n:查看当前源文件中第n行的代码
list InitializeJVM:查看InitializeJVM函数开始位置的代码
list:查看更多的行
list -:查看上次查看的代码行数之前的代码
默认,GDB打印10行。若需要调整,可使用:
set listsize n:调整打印行数为n行
查看栈帧:
frame n:从当前栈帧移动到#n栈帧
up n:从当前栈帧向上移动n个栈帧
down n:从当前栈帧向下移动n个栈帧
select-frame:查看更多的行
backstrace:查看整个调用栈
backstrace n:与backstrace类似,只不过只查看4个栈帧
backstrace full:查看整个调用栈,另外还打印出局部变量和参数
info args:查看函数参数
info locals:查看局部变量
查看数据:
print expr:查看expr的值,其中expr是源文件中的表达式
print /f expr n:以f指定的格式查看expr的值。其中f表示的格式可以为:
x:十六进制整数
d:有符号整数
u:无符号整数
o:八进制整数
t:二进制整数
c:字符常量
f:浮点数
s:字符串
r:原始格式
a:地址
x 0xbfffd034:查看内存地址为0xbfffd34的值
disassemble:查看汇编代码,反汇编当前函数
info registers:查看所有寄存器的值
print $eax:以十进制形式查看寄存器%eax的值
print /x $eax:以十六进制形式查看寄存器%eax的值

更多GDB的信息,可以参考GDB的官方教程1。

1.3.2 准备调试脚本

在HotSpot编译完成后,会在Jvmg目录下生成一个名为hotspot的脚本文件,如清单1-17所示。使用脚本可以替代大量重复性的输入,并且可以帮助我们准备好调试环境,为我们轻松调试系统创造了良好的环境。我们可以在此脚本文件的基础上调试HotSpot项目。

在启动调试之前,了解调试脚本究竟做了哪些工作是十分有益的,这有助于我们掌握独立分析和解决问题的能力,在出现问题时不致于手忙脚乱,可以利用自身所学知识解决问题。

清单1-17
来源:hotspot/src/os/posix/launcher/launcher.script
描述:调试脚本

#!/bin/bash```
首先是对传入的调试器名称参数进行转换,以便于定位到指定的调试器,支持的调试器包括GDB、GUD、DBX和VALGRIND等。

This is the name of the gdb binary to use

if [ ! "$GDB" ]
then
GDB=gdb
fi

This is the name of the gdb binary to use

if [ ! "$DBX" ]
then
DBX=dbx
fi

This is the name of the Valgrind binary to use

if [ ! "$VALGRIND" ]
then
VALGRIND=valgrind
fi

This is the name of Emacs for running GUD

EMACS=emacs```
用户可以通过调用该脚本时传入参数选择熟悉的调试器,这些参数可以是“-gdb”、“-gud”、“-dbx”或“-valgrind”。

# Make sure the paths are fully specified, i.e. they must begin with /.
SCRIPT=$(cd $(dirname $0) && pwd)/$(basename $0)
RUNDIR=$(pwd)

# Look whether the user wants to run inside gdb
case "$1" in
    -gdb)
        MODE=gdb
        shift
        ;;
    -gud)
        MODE=gud
        shift
        ;;
    -dbx)
        MODE=dbx
        shift
        ;;
    -valgrind)
        MODE=valgrind
        shift
        ;;
    *)
        MODE=run
        ;;
esac```
${MYDIR}是配置脚本的绝对路径:

Find out the absolute path to this script

MYDIR=$(cd $(dirname $SCRIPT) && pwd)```
${JDK}用来配置JDK路径,此外,还有一些链接库路径需要配置:

JDK=
if [ "${ALT_JAVA_HOME}" = "" ]; then
    source ${MYDIR}/jdkpath.sh
else
    JDK=${ALT_JAVA_HOME%%/jre};
fi

if [ "${JDK}" = "" ]; then
    echo Failed to find JDK. ALT_JAVA_HOME is not set or ./jdkpath.sh is empty or not found.
    exit 1
fi

# We will set the LD_LIBRARY_PATH as follows:
#     o        $JVMPATH (directory portion only)
#     o        $JRE/lib/$ARCH
# followed by the user's previous effective LD_LIBRARY_PATH, if
# any.
JRE=$JDK/jre
JAVA_HOME=$JDK
ARCH=i386

# Find out the absolute path to this script
MYDIR=$(cd $(dirname $SCRIPT) && pwd)

SBP=${MYDIR}:${JRE}/lib/${ARCH}

# Set up a suitable LD_LIBRARY_PATH

if [ -z "$LD_LIBRARY_PATH" ]
then
    LD_LIBRARY_PATH="$SBP"
else
    LD_LIBRARY_PATH="$SBP:$LD_LIBRARY_PATH"
fi

export LD_LIBRARY_PATH
export JAVA_HOME

JPARMS="$@ $JAVA_ARGS";```
${LAUNCHER}用作定位Launcher。关于Launcher,我们会在下一章中展开探讨。这里只需要知道它是虚拟机启动器程序便可:

Locate the gamma development launcher

LAUNCHER=${MYDIR}/gamma
if [ ! -x $LAUNCHER ] ; then
echo Error: Cannot find the gamma development launcher \"$LAUNCHER\"
exit 1
fi```
接下来是进行GDB自身初始化工作,包括配置工作路径以及信号等工作:

GDBSRCDIR=$MYDIR
BASEDIR=$(cd $MYDIR/../../.. && pwd)

init_gdb() {
# Create a gdb script in case we should run inside gdb
    GDBSCR=/tmp/hsl.$$
    rm -f $GDBSCR
    cat >>$GDBSCR <<EOF
cd `pwd`
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
set args $JPARMS
file $LAUNCHER
directory $GDBSRCDIR```
在这里,可以设置断点。选择你感兴趣的HotSpot项目源代码位置,如JVM初始化模块“InitializeJVM”函数入口。接下来,便可以利用GDB的break命令设置断点,如:

Get us to a point where we can set breakpoints in libjvm.so

break InitializeJVM
run

Stop in InitializeJVM

delete 1

We can now set breakpoints wherever we like

EOF
}```
剩余配置代码我们可以不做调整:

case "$MODE" in
    gdb)
    init_gdb
        $GDB -x $GDBSCR
    rm -f $GDBSCR
        ;;
    gud)
    init_gdb
# First find out what emacs version we're using, so that we can
# use the new pretty GDB mode if emacs -version >= 22.1
    case $($EMACS -version 2> /dev/null) in
        GNU\ Emacs\ 2[23])
        emacs_gud_cmd="gdba"
        emacs_gud_args="--annotate=3"
        ;;
        *)
        emacs_gud_cmd="gdb"
        emacs_gud_args=
        ;;
    esac
        $EMACS --eval "($emacs_gud_cmd \"$GDB $emacs_gud_args -x $GDBSCR\")";
    rm -f $GDBSCR
        ;;
    dbx)
        $DBX -s $MYDIR/.dbxrc $LAUNCHER $JPARAMS
        ;;
    valgrind)
        echo Warning: Defaulting to 16Mb heap to make Valgrind run faster, use -Xmx for larger heap
        echo
        $VALGRIND --tool=memcheck --leak-check=yes --num-callers=50 $LAUNCHER -Xmx16m $JPARMS
        ;;
    run)
        LD_PRELOAD=$PRELOADING exec $LAUNCHER $JPARMS
        ;;
    *)
        echo Error: Internal error, unknown launch mode \"$MODE\"
        exit 1
        ;;
esac
RETVAL=$?
exit $RETVAL```
至此,调试脚本已经准备就绪,接下来,让我们开始HotSpot的调试吧。输入命令:

sh hotspot –gdb HelloWorld```
启动调试,将出现如图1-7所示的界面。

HotSpot运行在断点1(InitializeJVM)上停止下来,这时就可以利用前面提到的GDB命令尽情地控制HotSpot的运行了!

如果想让程序继续执行,输入continue命令使虚拟机正常运行下去,可以看到程序输出“Hello hotspot”并正常退出。感兴趣的读者可以亲自动手尝试一下。

建议读者结合源代码,利用GDB命令来跟踪调试HotSpot,查看系统运行时的内部数据和状态。这有两个好处:一方面,这能帮助我们将枯燥的阅读源码任务转换成有趣的虚拟机调试工作;另一方面,也能促进我们加深对HotSpot的理解。

时间: 2024-08-03 22:40:00

《HotSpot实战》—— 1.3 实战:在HotSpot内调试HelloWorld的相关文章

实战分析玉器类企业站站内优化

想要名列百度首页前茅并非简简单单几个因素就可以提高网站排名的.装备既要精良内功也要足够身后才可以更大限度的提高我们的网站排名,在很多站长论坛中有着很多讨论站内优化的帖子,Q小木科技为大家做一个实战性企业网站的站内优化分析以便大家参考! 一.网站头部   进入网站好我们看到的就是产品图片和顶部宣传语,而我用红色框圈起来的部分也就是该站所存在的问题. 1.顶部品牌与宣传语:它们2个所占的位置相对首页位置来说比例有点过大,进入首页后再加上下面的轮展图(幻灯片)几乎看不到一个产品. 在这样的情况下我们需

实战经验分享快速解决网站内页不收录的技巧

  网站的内容收录与否则影响着咱们优化长尾关键词的进度.首先在网站优化中,内容页不收录大部分原因是因为页面的一些关键因素影响着蜘蛛的爬行索引,同时也可能是内容的质量达不到搜索引挚收录的标准,比如采集内容.低质量内容.相似度高的内容.不利于蜘蛛爬行的页面框架.过多的无ALT标签的图片.FLASH等等,都会影响到页面的收录.那么针对页面不收录,静待其成是不可行的,主动出击寻找分析原因来解决这个问题,才不会让站点陷入长期只收录首页而不收录内页的困境. 笔者操作的一个站点,上线有半年了,一直只收录首页而

《HotSpot实战》—— 2.2 启动

2.2 启动 Launcher(启动器),是用来启动JVM和应用程序的工具.在这一节中,我们将看到HotSpot中提供了两种Launcher类型,分别是通用启动器和调试版启动器. 2.2.1 Launcher 通用启动器(Generic Launcher)是指我们比较熟悉的JDK命令程序:java(含javaw).java是由JDK自带的启动Java应用程序的工具.为启动一个Java应用程序,java将准备一个Java运行时环境(即JRE).加载指定的类并调用它的main方法.类加载的前提条件是

《HotSpot实战》—— 第 1 章 初识HotSpo

第 1 章 初识HotSpo "知止而后有定,定而后能静,静而后能安,安而后能虑,虑而后能得." -<大学> 本章内容 VM与HotSpot VM 开源项目OpenJDK与HotSpot项目 Java语言特性的发展,以及JCP和JSR的推动作用 Coin项目为Java 7贡献的新特性 GDB调试工具的基本使用方式 HotSpot工程的编译与调试方法 对于Java程序员来说,启动一个应用服务器是再平常不过的工作了.不知读者是否留意过,在启动应用服务器时,控制台可能会有关于Ho

MongoDB实战(2)工具集与特殊魔术方法

一.MongoDB启动方式 MongoDB除了支持命令行的启动方式还支持配置文件启动通过读取启动配置文件的方式来启动数据库比方说配置文件如下 则可以使用如下命令 ./mongod -f /etc/mongodb.conf MongoDB参数说明 dbpath: 数据文件存放路径每个数据库会在其中创建一个子目录用于防止同一个实例多次运行的mongod.lock也保存在此目录中. logpath 错误日志文件 logappend 错误日志采用追加模式默认是覆写模式 bind_ip 对外服务的绑定ip

如何利用Hotspot 2.0获利?

当今网络世界中最受热捧的莫过于Hotspot 2.0了.对Hotspot 2.0的关注主要集中在技术本身及其工作原理上,而真正引人注目的"特色"还没有被人认识到,或者没有人完全搞懂.那就是该技术可以创造价值,而且相当丰厚.Hotspot 2.0到底是怎么一回事?Hotspot 2.0是由 Wi-Fi 联盟成员制定的一项规范,可极大地方便用户安全连接到Wi-Fi网络,而且可通过安全连接.自动化和符合用户与运营商策略有效地复制移动电话体验,从而实现不同Wi-Fi网络间的漫游.其发展背后蕴含

Bootstrap开发实战之第一次接触Bootstrap_javascript技巧

本文我们主要了解一下 Boostrap 历史.特点.用途,以及为什么选择 Boostrap 来开发我们的 Web 项目. 学习要点:1.Bootstrap 概述 2.Bootstrap 特点 3.Bootstrap 结构 4.创建第一个页面 5.学习的各项准备 一.Bootstrap 概述Bootstrap 是由 Twitter 公司(全球最大的微博)的两名技术工程师研发的一个基于HTML.CSS.JavaScript 的开源框架.该框架代码简洁.视觉优美,可用于快速.简单地构建基于 PC 及移

JavaScript使用DeviceOne开发实战(三)仿微信应用_javascript技巧

这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际App.  在实现的过程中,会有很多困难,还会发现有一些功能目前缺乏组件支持而无法实现,也会碰见各种移动开发中都会碰到的常见技术问题.一步一步的操作和问题的解决可以让开发者直观的了解通过DeviceOne如何开发一个实际App,也可以了解移动开发本身的很多技术细节,可以让App开发者少走很多弯路.

Bootstrap作品展示站点实战项目2_javascript技巧

假设我们已经想好了要给自己的作品弄一个在线站点.一如既往,时间紧迫.我们需要快一点,但作品展示效果又必须专业.当然,站点还得是响应式的,能够在各种设备上正常浏览,因为这是我们向目标客户推销时的卖点.这个项目可以利用Bootstrap的很多内置特性,同时也将根据需要对Bootstrap进行一些定制. 1.设计目标 虽然对大屏幕中的展示效果已经胸有成竹,但我们还应该从小设备开始,强迫自己聚焦在关键的要素上面. 这个作品展示站点应该具有下列功能: □ 带Logo的可折叠的响应式导航条: □ 重点展示四