在IntelliJ IDEA中调试超时

时间:2018-06-18 19:50:06

标签: java intellij-idea breakpoints systemtime

在我的应用程序中,如果不确定是否在合理的时间内满足条件,我会使用超时退出某些无限循环。

为了计时,我使用系统的时间,因为它很简单:

public class BenchmarkTimer
{
    private long startTime;

    public BenchmarkTimer()
    {
        startTime = System.currentTimeMillis();
    }

    public boolean isExpired(long milliseconds)
    {
        long executionTime = currentTimeMillis() - startTime;
        return executionTime > milliseconds;
    }
}

然而,在调试时,我不希望在应用程序冻结时继续时间。这显然不会默认工作,因为即使在断点期间系统时间也会继续。由于我在断点上花了很长时间才能继续,因此我不想进入超时状态,因为在正常的应用程序执行情况下,这会有不同的行为(例如,它会在#34之前执行更多尝试;放弃")

这个问题有什么解决方案吗? IntelliJ IDEA只能在断点期间暂停Java应用程序可见的系统时间吗?我希望调试的行为类似于常规执行,包括超时,因此我不确定如何实现这一点。

2 个答案:

答案 0 :(得分:0)

Ran评论的链接给了我正确的想法: 运行一个线程,如果Thread.sleep()睡得足够短,就会一直检查,否则事情很可疑,我们可能会遇到断点,所以我们可以“阻止”时钟,并在再次请求系统时间时返回更旧的时间

import lombok.val;

import static com.mycompany.SystemTimeBreakpointFixer.getCurrentTimeMillis;
import static com.mycompany.SystemTimeBreakpointFixer.considerRunningTimerFixerThread;
import static java.lang.System.currentTimeMillis;
import static java.lang.management.ManagementFactory.getRuntimeMXBean;

public class BenchmarkTimer
{
    private long startTime;

    static
    {
        considerRunningTimerFixerThread();
    }

    public BenchmarkTimer()
    {
        startTime = getCurrentTimeMillis();
    }

    public boolean isExpired(long milliseconds)
    {
        val currentTimeMillis = getCurrentTimeMillis();
        val executionTime = currentTimeMillis - startTime;
        return executionTime > milliseconds;
    }

    static class SystemTimeBreakpointFixer
    {
        private static final String THREAD_NAME = "System Time Fixer";
        private static final int CHECKING_DELAY = 100;
        private static final int NON_BREAKPOINT_DELAY = 100;
        private static final String DEBUGGING_INPUT_ARGUMENT = "-agentlib:jdwp";
        private static final boolean ARE_WE_DEBUGGING;

        static
        {
            ARE_WE_DEBUGGING = areWeDebugging();
        }

        private static boolean areWeDebugging()
        {
            val runtimeMXBean = getRuntimeMXBean();
            val inputArguments = runtimeMXBean.getInputArguments();
            val jvmArguments = inputArguments.toString();
            return jvmArguments.contains(DEBUGGING_INPUT_ARGUMENT);
        }

        private static long totalPausedTime = 0;
        private static Thread thread;

        static long getCurrentTimeMillis()
        {
            sleepThread();
            val currentTimeMillis = currentTimeMillis();
            return currentTimeMillis - totalPausedTime;
        }

        static void considerRunningTimerFixerThread()
        {
            if (ARE_WE_DEBUGGING && thread == null)
            {
                startTimerFixerThread();
            }
        }

        private static void startTimerFixerThread()
        {
            thread = new Thread(() ->
            {
                //noinspection InfiniteLoopStatement
                while (true)
                {
                    val currentMilliseconds = currentTimeMillis();
                    sleepThread();
                    val updatedMilliseconds = currentTimeMillis();
                    val currentPausedTime = updatedMilliseconds - currentMilliseconds - CHECKING_DELAY;
                    if (currentPausedTime > NON_BREAKPOINT_DELAY)
                    {
                        totalPausedTime += currentPausedTime;
                    }
                }
            });

            thread.setName(THREAD_NAME);
            thread.start();
        }

        private static void sleepThread()
        {
            try
            {
                Thread.sleep(CHECKING_DELAY);
            } catch (InterruptedException exception)
            {
                exception.printStackTrace();
            }
        }
    }
}

还可以参考this文章了解调试器检测。

答案 1 :(得分:0)

在带有返回值的行的isExpired内部使用断点并设置:

  • 设置“评估并记录”表达式,例如executionTime = 0
  • 取消设置“暂停”

现在处于调试模式,它将修改执行时间,以便isExpired始终返回false