5

所以,我正在启动一个Java程序,如下所示

java -agentlib:jdwp=transport=dt_socket,address=8000, server=y,suspend=n  MyClass

然后我手动附加一个调试器,如下所示

jdb -attach 8000

我想知道是否有任何方法让我设置 jdb 以便在未捕获异常的情况下(仅)自动附加到正在运行的进程?

原因是我想避免调试器的开销,直到出现未捕获的异常。但是我现在面临的问题是,如果没有附加调试器,那么一旦出现未捕获的异常,JVM 就会中止。

编辑:

从 Oracle docs看来,以下命令可以满足我的需要,但适用于 Windows 机器。

java -agentlib:jdwp=transport=dt_shmem,server=y,onuncaught=y,launch=d:\bin\debugstub.exe MyClass

有谁知道linux的等价物吗?我已经尝试了以下命令。

java -agentlib:jdwp=transport=dt_socket,address=8000,server=y,onuncaught=y,suspend=n,launch=jdb MyClass

调试器似乎已连接,但它立即抛出 IOError。

Initializing jdb ...

java.io.IOException: Input/output error
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:272)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at com.sun.tools.example.debug.tty.TTY.<init>(TTY.java:751)
at com.sun.tools.example.debug.tty.TTY.main(TTY.java:1067)
4

2 回答 2

3

及时附加调试器确实使用了您建议的选项(launchonuncaught)。但是启动选项在 linux 上需要更多:

请注意,启动的进程不是在其自己的窗口中启动的。在大多数情况下,启动的进程应该是一个小应用程序,它依次在自己的窗口中启动调试器应用程序。

在您的情况下,jdb 无法打开TTY它需要的终端,因为它正在启动它。根据运行它的环境,您将需要构建一个脚本,在新窗口中启动 jdb 或将其附加到一个pseduo-tty,以便它可以正常运行。

我通过创建一个使用screen启动终端的脚本来测试这一点

#!/bin/bash
# according to launch option doc, the first argument is the transport and
# the second argument will be the address
#
screen -dm -L -S autojdb jdb -attach $2

该脚本将jdb在一个分离的屏幕中启动,并为该屏幕命名会话autojdb。您可以使用 来查看屏幕列表screen -ls。当您想访问已启动的调试器时,请使用screen -r autojdb. 确保将脚本放在您的路径中或/home/me/screenjdb在您的启动选项中提供完整路径(如下):

java -agentlib:jdwp=transport=dt_socket,address=8000,server=y,onuncaught=y,suspend=n,launch=/home/me/screenjdb MyClass

在我的脚本中,我还传递-L到了记录会话的屏幕。这将记录会话,但也可以让您查看由于某种原因附加失败时发生的任何错误。

于 2015-02-27T15:42:18.093 回答
0

与其使用调试器并远程附加一个调试器,不如使用创建一个未捕获的异常处理程序Thread.UncaughtExceptionHandler

public class ThreadCatch
{
    public static void main(String... args)
    {
        new ThreadCatch().go();
    }

    public void go()
    {
        try {
            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println("Uncaught exception");
                    e.printStackTrace();
                }
            });

            final Thread thread = new Thread(new A());
            thread.start();
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    class A implements Runnable
    {
        int x = 10;

        @Override
        public void run()
        {
            x++;
            ObjectTrackingException obj = new ObjectTrackingException();
            obj.setThrownFrom(this);
            throw obj;
        }
    }
}


class ObjectTrackingException extends RuntimeException
{
    private Object thrownFrom;

    public Object getThrownFrom() {
        return thrownFrom;
    }

    public void setThrownFrom(Object thrownFrom) {
        this.thrownFrom = thrownFrom;
    }
}

在此处输入图像描述

于 2015-02-15T16:54:22.800 回答