Java 在未捕获异常上附加jdb

Java 在未捕获异常上附加jdb,java,debugging,jdb,Java,Debugging,Jdb,因此,我启动了一个Java程序,如下所示 java -agentlib:jdwp=transport=dt_socket,address=8000, server=y,suspend=n MyClass 然后手动附加一个调试器,如下所示 jdb -attach 8000 我想知道,我是否需要设置jdb,以便在出现未捕获异常的情况下,它自动连接到正在运行的进程(仅限于) 原因是我希望在出现未捕获的异常之前避免调试器的开销。但我现在面临的问题是,如果没有连接调试器,那么一旦出现未捕获的异常,J

因此,我启动了一个Java程序,如下所示

java -agentlib:jdwp=transport=dt_socket,address=8000, server=y,suspend=n  MyClass
然后手动附加一个调试器,如下所示

jdb -attach 8000
我想知道,我是否需要设置jdb,以便在出现未捕获异常的情况下,它自动连接到正在运行的进程(仅限于)

原因是我希望在出现未捕获的异常之前避免调试器的开销。但我现在面临的问题是,如果没有连接调试器,那么一旦出现未捕获的异常,JVM就会中止

编辑:

从Oracle来看,下面的命令似乎满足了我的需要,但适用于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)
正在初始化jdb。。。
java.io.IOException:输入/输出错误
位于java.io.FileInputStream.readBytes(本机方法)
在java.io.FileInputStream.read(FileInputStream.java:272)处
位于java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
在java.io.BufferedInputStream.read处(BufferedInputStream.java:334)
位于sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
位于sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
位于sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
位于java.io.InputStreamReader.read(InputStreamReader.java:184)
在java.io.BufferedReader.fill中(BufferedReader.java:154)
位于java.io.BufferedReader.readLine(BufferedReader.java:317)
位于java.io.BufferedReader.readLine(BufferedReader.java:382)
位于com.sun.tools.example.debug.tty.tty.(tty.java:751)
位于com.sun.tools.example.debug.tty.tty.main(tty.java:1067)

与其使用调试器并远程附加调试器,不如使用
线程创建一个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;
    }
}

要及时附加调试器,确实会使用您建议的选项(
launch
onuncought
)。但该选项在linux上需要更多:

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

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

我通过创建用于启动终端的脚本对此进行了测试

#!/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
传递给记录会话的屏幕。这将记录会话,但也可以让您看到由于某种原因连接失败时发生的任何错误。

好吧,我想分析程序崩溃时堆栈上变量的值。我不认为我可以用UncaughtExceptionHandler实现这一点,因为堆栈将随着异常向上传递而展开?那么为什么不在异常处理程序上设置一个条件断点呢?这样,您就可以捕获异常,断点允许您浏览调用堆栈。因此,据我所知,当从方法B抛出异常时,该方法的调用堆栈将被销毁,异常将向上抛出。这将继续进行,直到异常最终到达UncaughtExceptionHandler。但此时,异常最初发生的方法的调用堆栈(我想查看其局部变量)已不存在。那么条件断点就没用了?如果我的理解有什么问题,请告诉我……啊,我没意识到你想看看局部变量。如果您感兴趣的是对象状态,那么您可以始终将其保存在异常中,并将其向上传播。我已经编辑了我的示例来处理这个用例。这有助于解决你的问题吗?