`

Linux_Macintosh 平台下 Eclipse 环境中的 JNI 混合语言调试

阅读更多

Linux_Macintosh 平台下 Eclipse 环境中的 JNI 混合语言调试

developerWorks
文档选项
<script type="text/javascript"></script> <noscript></noscript> <script type="text/javascript"></script> <noscript></noscript>
将打印机的版面设置成横向打印模式

打印本页

将此页作为电子邮件发送

将此页作为电子邮件发送

<!----><!----><!---->

级别: 初级

张 垚 (yaozhang@cn.ibm.com), 软件工程师, IBM

2008 年 4 月 17 日

在当今的应用程序开发尤其是大型程序开发中,混合语言的使用已经是相当普 遍了。在 Java 应用程序开发中,程序员可以很方便的使用 JNI(Java Native Interface) 来实现 C/C++ 和 Java 代码的相互调用。本文简要介绍了在 Linux/Macintosh 平台上针对 JNI 的混合语言调试环境的搭建以及调试方法,并通过一个调试实例来给读者提供一个比较直观的演示。
<!----><!----><!---->

简介

在当今的应用程序开发尤其是大型程序开发中,混合语言的使用已经是相当普遍了。在 Java 应用程序开发中,程序员可以很方便的使用 JNI(Java Native Interface) 来实现 C/C++ 和 Java 代码的相互调用。在一些大型 C/C++ 项目向 Java 的迁移过程中,将一部分代码用 Java 重写,并使用 JNI 来保持功能性是一种采用较多的可控性比较强的设计。

本文简要介绍了在 Linux/Macintosh 平台上针对 JNI 的混合语言调试环境的搭建以及调试方法,并通过一个调试实例来给读者提供一个比较直观的演示。

在 Linux/Macintosh 平台上, Eclipse JDT 是最好的 Java 开发集成环境之一。读者如果想了解更多 JDT 相关信息,可以去 http://www.eclipse.org/jdt/ 看一下,本文只会介绍和调试相关的内容。





回页首


JNI 混合语言调试

Linux/Macintosh 平台下 Eclipse 环境中的 JNI 混合语言调试过程分为两部分,第一部分是在 Eclipse JDT 环境中对 Java 代码的调试,第二部分则是当程序运行到 C/C++ 代码部分是用 gdb 对 C/C++ 代码的调试。





回页首


在 Eclipse 集成环境中调试 Java 代码

在 Eclipse 中启动 Java 程序并进行调试,主要有两种方式:本地调试和远程调试。本地调试就是直接从本机的 Eclipse 环境中启动 Java 程序进行调试。远程调试是 attach 到网络远程机器上运行的 java 程序,并进行调试。这两种调试方法有各自的适用范围。

本地调试一般适用于程序员的开发环境,并且调试内容不依赖与 UI 事件。本地调试的好处在于你可以完整的调试整个应用程序的生命周期,从一开始启动到程序退出。

远程调试则主要在两种情况下使用。1)被调试的 Java 程序所运行的机器上没有也无法安装 Eclipse, 比如客户机器上运行的产品。2)所调试的 Java 程序内容依赖于某些 UI 事件,比如焦点切换等等。远程调试必须在被调试的程序已经运行起来后,才能 attach 并进行调试,因此它无法完整的调试应用程序的整个生命周期。

本地调试

在开始调试之前,你需要做一些配置工作。

  1. 首先启动 Eclipse 并切换到 JDT 视图。
    1. 点击 Window 菜单。
    2. 点击 Open Perspective 菜单项。
    3. 在 Open Perspective 的子菜单中点击 Java 项。

图1 Open Perspective 的子菜单中的 Java 项
Open Perspective 的子菜单中的 Java 项
  1. 打开调试设置对话框。
    1. 点击 Run 菜单。
    2. 点击 Open Run Dialog 菜单项。

图2 Open Run Dialog 菜单项
Open Run Dialog 菜单项
  1. 根据调试的 Java 应用程序选择调试类型,常用的有:
    1. Eclipse Application
    2. Java Applet
    3. Java Application

图3 Java 应用程序选择调试类型
Java 应用程序选择调试类型

这里我们以 Java Application 为例。接下来你需要设置相关的程序启动参数。

  1. 首先需要设置 Main Class 相关参数,在 Debug 对话框中点击 Main 页面:

图4 Debug 对话框的 Main 页面
Debug 对话框的 Main 页面
  1. 在 Project 一栏中填入你想要调试的项目名称,你可以通过点击 Browse… 按钮来在当前 workspace 中选择项目。
  2. 在 Main class 一栏中填入你要调试的Java Main class, 你可以点击 Search… 按钮来 在当前 Workspace 里所有实现 main 方法的 class 中进行搜索。
  3. 在 Arguments 页面里,你可以设置程序启动的相关参数以及 JVM 的参数。

图5 设置程序启动相关参数以及 JVM 参数
设置程序启动相关参数以及 JVM 参数
  1. 在 JRE, Classpath, Source, Environment 以及 Common 中还可以设置其他参数,这里就不详细叙述了,读者可以自行参考 Eclipse 帮助文档的 Java Development User Guide 部分。
  2. 调试启动参数设置完毕以后,就可以点击 Debug 按钮来启动程序进行调试了。

远程调试

远程调试的设置则相对简单。

  1. 远程机器上运行的被调试程序必须在启动时添加如下的JVM参数:

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

这里有两点需要说明一下

1)address=8000 中的 8000 指的是端口号,你也可以指定别的未使用的端口号,调试机器需要在 Eclipse 中配置相同的端口号才能成功连接。

2)请注意参数的逗号前后是没有空格的。

  1. 在调试机器上重复本地调试步骤中的1至3步,并选择 Remote Java Application 这种调试类型。

图6 Remote Java Application 调试类型
Remote Java Application 调试类型
  1. 在 Connect 页面的 Connection Properties 中,Host 里填入被调试程序所在机器的 IP 地址,在 Port 里填入第 1 步中所制定的端口号。
  2. 在 Source 页面里,你可以指定源文件的目录。在远程调试中,调试机器不需要有被调试程序的可执行文件,只要有源文件就可以了。当然,如果你没有源文件,也可以 attach 上去,你可以看到现场的调用堆栈,但是无法进行单步执行等动作。

调试 Java 代码

无论是本地调试还是远程调试,在进行调试后就可以通过点击菜单 Windows->Open Perspective->Debug 来切换到 Debug Perspective。


图7 Open Perspective 的 Debug 菜单项
Open Perspective 的 Debug 菜单项

Debug Perspective 中主要包括 Debug, Editor, Outline, Variable, Breakpoint 和 Console 视图。


图8 Debug Perspective
Debug Perspective

具体每个视图的使用和常用的调试命令这里就不一一详细叙述了,读者可以参考 Eclipse 帮助文档的 Java Development User Guide 中相关的视图部分文档。

JNI 程序的纯 Java 代码部分的调试是和调试其他 Java 程序相同的,所不同的地方就是当调用到 native 方法的时候,再往里执行就会进入 C/C++ 代码,这时候就需要使用 gdb 来进行调试了,在下一节中会详细介绍。

Tips

在这里作者有几个在日常调试 Java 代码过程中总结的 Tips 和大家分享一下。

  • 在 native 方法上设置断点。

在 Eclipse 中显示的调用堆栈只包括 Java 的堆栈,C/C++ 的堆栈是看不见的。那么当你断在某个 native 方法的 C/C++ 实现中,却想要看到 Java 的调用堆栈,就可以通过在 Eclipse 中将断点设在 native 方法上,而不是某一代码行来达到目的。具体方法是在 Outline 视图或者 Editor 视图中选择欲设置断点的 native 方法,然后点击菜单 Run->Toggle Method Breakpoint 即可。当程序调用这个 native 方法是,会自动断在方法入口处。

  • 条件断点。

在某些情况下,条件断点的使用可以极大的提高调试效率。在 Eclipse 中设置条件断点的方法是:在 Breakpoint 视图中选择某个断点,在右键菜单中选择 Breakpoint Properties…,这时会弹出断点属性对话框。

在属性对话框中勾上 Enable Condition 项,就可以在文本框中输入条件表达式了。同时你还可以选择是当条件表达式为真是中断还是条件表达式的值变化的时候中断,以及是中断当前线程还是 JVM 中的所有线程。


图9 条件断点设置
条件断点设置
  • 异常断点。

在某些情况下,需要在程序抛出异常的时候及时中断,来获取异常发生时的现场。这可以通过设置异常断点来实现。

点击菜单 Run->Add Java Exception Breakpoint…,会显示异常断点设置对话框。


图10 异常断点设置
异常断点设置

输入设置的异常类型,点击 OK 按钮,异常断点就设置好了。





回页首


在终端中使用 Gdb 调试 C/C++ 代码

当 Java 代码执行到调用 native 方法的时候,再往下执行就会进入 native 方法的 C/C++ 实现了。这时我们需要使用 gdb 来调试 native 方法的 C/C++ 实现代码。

  1. 打开一个 Shell 窗口。如果是远程调试,你需要用 Shell 远程登录到被调试程序所在的机器上。
  2. 使用 ps 命令来得到被调试程序(java)的进程 id。
                  ps –ax |grep java


图11 获取被调试程序(java)的进程 id
获取被调试程序(java)的进程 id
  1. 然后运行如下命令来使用 gdb attach 到被调试的 java 进程上。
	gdb –pid=javapid


图12 用 gdb attach 到被调试的 java 进程
用 gdb attach 到被调试的 java 进程
  1. Attach 完毕后,你就可以像调试其他 C/C++ 程序那样调试 JNI native 方法的 C/C++ 代码了。

请注意,当你用 gdb attached 到 java 进程的时候, Eclipse 中的 Debug 视图会失去响应,此时你无法看到变量值或继续程序等等。直到你在 gdb 中使用 continue 命令继续程序执行时, Eclipse 中的 Debug 视图才会恢复响应。





回页首


一个调试实例

这一节将给读者具体演示一个 JNI 的本地调试实例。例子的运行环境是 Mac OSX 10.5, 代码非常简单,共包含两个文件 testrun.java 和 testjni.c。


代码1 testrun.java
                
package com.ibm.jni.test;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class testrun {
 public static void main(String[] args) {
 testrun tr = new testrun();
 Display display = Display.getDefault();
 Shell shell = new Shell(display);
 System.loadLibrary(“jnitest”);
 shell.open();
 int a = tr.jniexample();
 System.out.println(a);
 while ( !shell.isDiposed()){
 if ( !display.readAndDispatch() )
 display.sleep();
 }
    }
public native int jniexample();
}


代码2 jnitest.c
                
#include <jni.h>
#include <stdio.h>
#include <Carbon/Carbon.h>
JNIEXPORT jint JNICALL Java_com_ibm_jni_test_testrun_jniexample( JNIEnv *env, jclass that)
{
 printf(“this is in jni call\n”);
 return -1231;
}

testrun.java 是 java 主程序,其代码就是 load 由 testjni.c 生成的 libjnitest.jnilib 并调用其 jniexample 方法。

jnitest.c 则包含了 com.ibm.jni.test.testrun.jniexample 的 C 实现。调试实例步骤如下:

  1. 在 testrun.java 中设置断点,不妨设置在 testrun.java 的12行。
  2. 从 Eclipse中启动 testrun.java, 程序会断在步骤1中设置的断点上,并自动切换到 Debug Perspective。

图13 切换到 Debug Perspective
切换到 Debug Perspective

你可以查看当前的调用堆栈,线程,断点,变量值等等。

  1. 点击 Step Over 按钮或按 F6 键,程序会单步向前执行一条语句。
  2. 在 JNI C 代码中设置断点。打开一个 Shell 窗口,键入 ps –ax|grep java。

图14 获取 Java 进程 id
获取 Java 进程 id
  1. 键入 gdb –pid=90538,attach 到调试的 java 进程上。
  2. 键入 l testjni.c:7
  3. 键入 b testjni.c:7
  4. 键入 c

图15 Attach 到 java 进程并设置断点
Attach 到 java 进程并设置断点

C 代码中的断点已经设置完毕。

  1. 回到 Eclipse 界面中,点击 Resume 按钮或按 F8 键,继续 Java 程序运行。
  2. Eclipse 调试界面中会暂时失去响应,此时 gdb 已经断在我们前面设置的断点上。

图16 触发 gdb 断点
触发 gdb 断点

这时你可以像调试一个普通 C 程序那样进行调试。

  1. 键入 C,继续程序运行。




回页首


结束语

JNI 的混合语言调试是在编程过程中经常遇到的需求,在 Linux/Macintosh 平台上,Ecslipse 和 gdb 的混合使用功能强大而且使用方便。本文介绍了在 Linux/Macintosh 平台上针对 JNI 的混合语言调试环境的搭建以及调试方法,并结合一个具体实例演示了调试的基本过程,希望对读者有一点的帮助。

分享到:
评论

相关推荐

    08_17_JNI_04_JNI引用&缓存策略

    08_17_JNI_04_JNI引用&缓存策略08_17_JNI_04_JNI引用&缓存策略08_17_JNI_04_JNI引用&缓存策略08_17_JNI_04_JNI引用&缓存策略08_17_JNI_04_JNI引用&缓存策略08_17_JNI_04_JNI引用&缓存策略08_17_JNI_04_JNI引用&缓存...

    08_12_JNI_02_jni数据类型&属性方法

    08_12_JNI_02_jni数据类型&属性方法08_12_JNI_02_jni数据类型&属性方法08_12_JNI_02_jni数据类型&属性方法08_12_JNI_02_jni数据类型&属性方法08_12_JNI_02_jni数据类型&属性方法08_12_JNI_02_jni数据类型&属性方法08...

    08_15_JNI_03_方法访问_数组处理&jni引用

    08_15_JNI_03_方法访问_数组处理&jni引用08_15_JNI_03_方法访问_数组处理&jni引用08_15_JNI_03_方法访问_数组处理&jni引用08_15_JNI_03_方法访问_数组处理&jni引用08_15_JNI_03_方法访问_数组处理&jni引用08_15_JNI_...

    linux_ndk_eclipse调试

    通过以上步骤,你就能够在Linux环境下使用Eclipse和NDK进行原生代码的开发和调试了。这允许你充分利用C/C++的性能优势,同时借助Java的便利性来构建Android应用。在开发过程中,加入相关的QQ群与其他开发者交流,...

    serial_jni_largestgle_Androidjni_Android串口操作JNI代码_android_

    `serial_jni_largestgle_Androidjni_Android串口操作JNI代码_android_`这个项目就是关于如何使用JNI来实现Android设备的串口读写的示例。 首先,我们需要了解JNI的概念。JNI是Java平台提供的一种接口,允许Java代码...

    Eclipse_Jni_Opencv_NDK

    标题"Eclipse_Jni_Opencv_NDK"涉及的是在Eclipse环境下使用JNI(Java Native Interface)集成OpenCV库,并通过NDK(Native Development Kit)进行原生代码开发。这是一个关于Android平台上的混合编程实践,旨在利用...

    JNI_API.rar_android jni api_jni_jni api_jni api_jni api chm

    JNI(Java Native Interface)是Java平台的一个重要组成部分,它允许Java代码和其他语言写的代码进行交互。这个"JNI_API.rar"压缩包包含了一份关于Android JNI API的详细文档,以CHM(Compiled HTML Help)格式存在...

    Java_JNI_VCPP_details.rar_jni_jni vc

    Java本地接口(JNI)是Java平台的标准组成部分,它允许Java代码和其他语言编写的代码进行...提供的PDF文档"Java_JNI_VC++_details.pdf"应该会进一步深入探讨这些概念,并可能包含实际示例和最佳实践,建议仔细阅读。

    JniCallback.zip_Android jni_android_jni android_jni callback_jni

    在Android开发中,JNI(Java Native Interface)是一个关键的技术,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下都非常有用,比如优化性能、使用现有的C/C++库、或者像在这个“JniCallback.zip”文件...

    jni.rar_3GPP AMR jni_amr_ilbc_jni_jni amr

    标题中的"jni.rar_3GPP AMR jni_amr_ilbc_jni_jni amr"揭示了这个压缩包文件的核心内容,它涉及到Java平台下的JNI(Java Native Interface)技术,以及3GPP AMR(Adaptive Multi-Rate)音频编码格式和ILBC(Internet...

    JNI_Demo.rar_DEMO_JNI DEMO_jni c_jni dll_vc6 dll

    JNI(Java Native Interface)是Java平台的标准组成部分,它允许Java代码和其他语言写的代码进行交互。在本示例"JNI_Demo.rar"中,我们有一个演示如何使用JNI来调用C语言编写的动态链接库(DLL)的实例。这个DEMO是...

    JniDemo_H246分析_DEMO_jni测试_

    JNI(Java Native Interface)是Java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在Android开发中扮演着重要的角色,尤其是在涉及到性能优化、调用系统底层API或使用C/C++库时。本篇文章将通过分析...

    jni调试 c层在eclipse中输出信息

    本教程将详细介绍如何在C层利用JNI进行调试,并在Eclipse环境中输出信息。 首先,我们需要理解JNI的基本工作原理。JNI提供了一种方式让Java代码能够调用本地(Native)代码,也就是C/C++代码,同时本地代码也可以...

    JNI开发 eclipse相关开发环境的搭建

    本文将指导读者如何在 Eclipse 中搭建 JNI 开发环境,并使用 CDT 插件进行 C/C++ 代码的编写和编译。 环境搭建 1. 安装 CDT 插件 CDT(C/C++ Development Tooling)是 Eclipse 中的 C/C++ 开发插件。可以从官方...

    jni.zip_C++ JNI_JNI 调用java_c调用java_jni_jni jdk1

    在这个“jni.zip”压缩包中,我们主要探讨的是如何使用C++通过JNI来调用Java类,这是Java平台跨语言交互的一个重要技术。下面将详细介绍这个过程: 1. **JNI基本结构**: JNI接口定义了一组函数,这些函数允许本地...

    jni.rar_Android jni_Animation jni mk_jni_jni android

    标签中的“animation_jni_mk”提到了动画和mk文件。在Android中,JNI的链接过程会涉及到一个名为"Android.mk"的文件,这是一个Makefile,用于指示编译系统如何构建本地代码。在这个过程中,"Android.mk"文件定义了...

    JNI_md.rar_jni_jni_md

    例如,在Windows上,`JNIEnv`接口的实现可能与Linux或Mac OS有所不同,因此`jni_md.h`会包含这些平台特定的差异。 在提供的压缩包中,`www.pudn.com.txt`可能是下载来源的说明或链接,而`JNI_md`可能就是上述提及的...

    jni_demo.rar_DEMO_jni vc

    标题中的"jni_demo.rar_DEMO_jni vc"表明这是一个关于JNI (Java Native Interface)的示例,使用Visual C++(VC++)进行编程。JNI是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。这个RAR压缩包...

    08_10_C_06_预编译&jni开发流程

    08_10_C_06_预编译&jni开发流程08_10_C_06_预编译&jni开发流程08_10_C_06_预编译&jni开发流程08_10_C_06_预编译&jni开发流程08_10_C_06_预编译&jni开发流程08_10_C_06_预编译&jni开发流程08_10_C_06_预编译&jni开发...

    jni.zip_java jni_jni_jni-api_jni方面的书

    Java本地接口(JNI,Java Native Interface)是Java平台标准的一部分,它允许Java代码与其他语言写的代码进行交互。JNI在很多场景下都非常有用,比如当需要调用已有的C/C++库,或者利用硬件特性,或者优化性能时。本...

Global site tag (gtag.js) - Google Analytics