【问题标题】:How to Debug Java -JNI using GDB on linux ?如何在 Linux 上使用 GDB 调试 Java -JNI?
【发布时间】:2026-02-01 18:35:02
【问题描述】:

任何人都可以指导如何使用 GDB 调试器在 Linux 上调试 JNI 代码(如果可能,请建议其他选项)。

    -My JNI project when running on Linux is leading to a JVM crash.
    -The CPP code has been compiled into .so files.
    -I run the project like  this : *java xyz.jar -commandline_args_to_project*.

我安装了 Gdb,但不知道如何使用它调试项目。 我还必须使用 -g 选项 t 调试 .so 文件来编译 .cpp 文件吗?

【问题讨论】:

    标签: java linux gdb java-native-interface shared-libraries


    【解决方案1】:
    1. 启动您的 java 应用程序
    2. 使用 top、ps、... 查找 pid
    3. 用这个 pid 启动 gdb
    4. 附上您的程序代码
    5. 像往常一样使用 gdb 进行调试

    这个博客post 解释了整个事情。

    【讨论】:

    • :我在link 找到了另一种方法。通过这种方式,我能够从 GDB 内部调试启动我的项目,因此不需要切换不同的 shell。
    【解决方案2】:

    我发现以下方式非常有趣。通过将下面的文件链接到您要调试的 jni 库,当动态链接器加载该库时,由于 gcc 构造函数属性,它会自动为当前 jvm 启动一个 gdbserver。

    只需从命令行或 Eclipse 中使用远程 gdb,即可轻松调试。我只设置如果我在调试模式下构建,我暂时还没有实现检测 jvm 是否在调试中启动,目前只允许这样做,但可能很容易。

    我只是从这里的文章中改编了这个概念:http://www.codeproject.com/Articles/33249/Debugging-C-Code-from-Java-Application

    #ifndef NDEBUG // If we are debugging
    
    #include <stdlib.h>
    #include <iostream>
    #include <sstream>
    
    namespace debugger {
        static int gdb_process_pid = 0;
    
        /**
         * \brief We create a gdb server on library load by dynamic linker, to be able to debug the library when java begins accessing it.
         * Breakpoint have naturally to be set.
         */
        __attribute__((constructor))
        static void exec_gdb() {
            // Create child process for running GDB debugger
            int pid = fork();
    
            if (pid < 0) {
                abort();
    
            } else if (pid) {
                // Application process
    
                gdb_process_pid = pid; // save debugger pid
                sleep(10); /* Give GDB time to attach */
    
                // Continue the application execution controlled by GDB
            } else /* child */ {
                // GDBServer Process
    
                // Pass parent process id to the debugger
                std::stringstream pidStr;
                pidStr << getppid();
    
                // Invoke GDB debugger
                execl("/usr/bin/gdbserver", "gdbserver", "127.0.0.1:11337", "--attach", pidStr.str().c_str(), (char *) 0);
    
                // Get here only in case of GDB invocation failure
                std::cerr << "\nFailed to exec GDB\n" << std::endl;
            }
        }
    }
    #endif
    

    此外,它还允许在安装了 gdbserver 并在您的开发电脑上安装 gdb-multiarch 的嵌入式设备上进行调试。

    在 Eclipse 中进行调试时,它会在 C/C++ 调试器和 Java 调试器之间自动跳转。您只需启动两个调试会话:java 一个和远程 C/C++ 一个,在 127.0.0.1:11337 上运行。

    【讨论】:

      【解决方案3】:

      Link by tm.sauron 是对的但是当我们有很多参数要传递给 java 命令时会不太方便,比如我的项目有大约几行参数要传递。因此,在这种情况下,我们可以使用 IDE 启动应用程序,并在我们想要在本机库中进行调试时将其中断。当然原生库需要在调试模式下创建。

      【讨论】: