Various tricks of DEBUG in IDEA

The Debug functions of various IDEs in Java are implemented through the Java Platform Debugger Architecture (JPDA) provided by Java .

With the help of the Debug function, you can easily debug the program and quickly simulate/find the errors in the program.

The Debug function of Interllij Idea says that although it looks similar to Eclipse, it is still much better than Eclipse in terms of user experience.

In Debug, the most commonly used is the next step, the next breakpoint (Breakpoint), several operations to view the running value; but in addition to these IDEs also provide some "advanced" functions, which can help us debug more conveniently

Java8 Streams Debug

As a highlight of Java 8, Stream is a completely different concept from InputStream and OutputStream in the java.io package. Stream in Java 8 is an enhancement to the function of Collection objects. It focuses on various very convenient and efficient aggregate operations or bulk data operations on collection objects.

IntStream.iterate(1, n -> n + 1)
                .skip(100)
                .limit(100)
                .filter(PrimeFinder::isPrime)//检查是否是素数
                .forEach(System.out::println);
复制代码

The above code is a common usage of streams, sorting the collection and converting values. Idea also provides the function of analyzing the stream process



Modify the program execution flow

In the Debug process, in general, just let the program execute normally. However, in some cases, it is necessary to dynamically modify the execution process. At this time, it is too inconvenient to modify the code. Fortunately, Idea provides some functions to dynamically modify the program execution process, which allows us to debug flexibly.

Return to the previous stack frame/delete the current stack frame/"Drop frame"

When we were trembling when we were debugging, we missed the breakpoint in advance or by pressing the wrong next step. At this time, you can use the Drop Frame function provided by Idea to return to the previous stack frame

The virtual machine stack describes the memory model of Java method execution: when each method is executed, a stack frame (Stack Frame) [illustration] is used to store information such as local variable table, operand stack, dynamic link, method exit, etc. . The process of each method from invocation to completion of execution corresponds to the process of pushing a stack frame in the virtual machine stack to popping out of the stack.

In fact, it is not only Java, but the method execution model of other programming languages ​​is also a stack structure. The execution of the method corresponds to a push/pop operation.

For example, in the following code, when the method is executed once, there are two methods on the stack frame

At this point, after clicking the Drop Frame button, the data on the top of the stack will be deleted and return to the position before the log method was called

Note: Although the Drop Frame is easy to use, some irreversible problems may occur after the Drop Frame, such as IO operations, or modified shared variables that cannot be rolled back, because this operation only deletes the stack frame at the top of the stack, and Not really "reverse operation"

Force Return

When a method is relatively long, or Step Info reaches a less important method and wants to skip the method, you can use the Force Return function to force the end of the method

Note: Force Return is not the same as Step Out. Step Out is to jump out of the current step or execute the code in the method; and Force Return is to force the end of the method directly, skipping all the code after the method and return directly. For example, the following code, when Force Return is used, the println in the evaluate method will not be executed

When the method to be forced to return has a return value (not void), force return also needs to specify a return value

Trigger exception

When the called method may throw an exception and the caller needs to handle the exception, you can directly let the method throw an exception without modifying the code

The following is a piece of pseudo code, which simulates sending a request, and automatically retry after timeout

When the method is executed to sendPacket, the Throw Exception operation can be executed to end the method early and throw the specified exception

After the caller receives the exception, he can execute the retry logic in catch, so there is no need to modify the program to simulate the exception, which is very convenient

Debug the running JVM process (Attach to Process)

When the application cannot be run in Idea and you want to debug the running program, you can use the Attach to Process function, which can debug the running program. Of course, the premise is to ensure the running JVM process code Consistent with the code in Idea

This kind of scenario is actually quite common. For example, when you want to debug springboot executable jar, or debug independent deployment and running processes such as tomcat source code, it is very convenient to pass Attach to Process. You can use the environment other than Idea + Idea Debug the code

This kind of function is actually also available under C/C++ GDB, Debug is only the running program, Intellij Clion also supports

Remote Debug

Remote debugging is a function provided by the JVM, similar to the Attach to Process above, except that the process has changed from local to remote

For example, our program has no problem locally, but there is a problem on the server; for example, the local is MacOs, the server is Centos, and the environment is different, which leads to some bugs. At this time, you can use the remote debugging function to debug

If you want to enable remote debugging, you need to add the following parameters to the startup script of the remote JVM process:

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
复制代码

The suspend parameter indicates whether the JVM process has been started in "suspended" mode. If it is started in "suspended" mode, the JVM process will block and not continue execution until the remote debugger connects to the process.

This parameter is very useful. For example, if our problem occurs during JVM startup (such as Spring's loading/initialization process), we need to set suspend to y, so that the JVM process will wait for the remote debugging connection in Ide to complete before continuing. run. Otherwise, the remote JVM has been running for a period of time, and the IDE’s Debugger is only connected, and the time for the breakpoint has already been missed.

After the remote JVM process is configured in the Debug mode and started, you can connect in Idea, and create a new Remote Configuration in the Run/Debug Configurations panel of Idea:

Then configure the Host/Port and click Apply to save

Finally, start the remote JVM process first, and then Debug in Idea to run the Configuration just configured

Tips: Under remote debugging, due to the network overhead, the response will be slower and the remote program will be suspended. Please find an environment where no one is using it.

Debugging under multithreading

Multi-threaded programs are more difficult to write. To be precise, it is difficult to debug. If you are not careful, you will cause various bugs due to thread safety issues, and these bugs may be difficult to reproduce. Because the thread scheduling of the operating system is beyond our control, the errors of multithreaded programs are very random, and it is difficult to find once a problem occurs; our program may be normal in 99.99% of the cases, but the final 0.01% is also likely to cause serious errors

The most common problem of thread safety is race conditions. When some data is modified by multiple threads at the same time, thread safety problems may occur.

For example, in the following process, the program is no problem under normal circumstances

When there is a competition problem, between the read and write operations of a single thread, other threads are scheduled, and the data will be wrong at this time

The following is a sample code. Although the shared data a is a synchronizedList, it does not guarantee that addIfAbsent is an atomic operation, because contains and add are two synchronized methods, and the execution gap between the two methods may still be modified by other threads.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ConcurrencyTest {
    static final List a = Collections.synchronizedList(new ArrayList());

    public static void main(String[] args) {
        Thread t = new Thread(() -> addIfAbsent(17));
        t.start();
        addIfAbsent(17);
        t.join();
        System.out.println(a);
    }

    private static void addIfAbsent(int x) {
        if (!a.contains(x)) {
            a.add(x);
        }
    }
}
复制代码

If Debug this code, after a Step Over (next step), the scope of this next operation is the entire process, not the current thread. In other words, after the next step of Debug, it is likely to be inserted and modified by other threads. This shared data a is equally unsafe, and the problem of repeatedly adding element 17 is likely to occur.

However, the above-mentioned problems are only possible and difficult to reproduce during actual debugging. Idea's Debug can set the suspension granularity to thread instead of the entire process

After Suspend is set to Thread, as shown in the figure below, set the breakpoint on the a.add line, and then run the program in Debug mode, the main thread and the newly created thread will hang in the addIfAbsent method, we can Debug in Idea Switch threads in the panel

At this point, both the Main thread and the child thread have called the contains method, and both return false, and hang on the a.add line, and they are ready to add 17 to a

After executing the next step, the Main thread successfully added 17 to the collection

Switching to Thread-0 thread at this time, it still hangs on the line a.add(x), but there is already element 17 in set a, but the Thread-0 thread will continue to add, and set a repeats after add Element 17, causing a bug in the program

As can be seen from the above example, in the process of debugging a multi-threaded program, the Suspend function of Idea Debug can be used to easily simulate the problem of multi-threaded competition, which is very convenient for writing or debugging multi-threaded programs.


Author: empty
link: https: //juejin.cn/post/6943019660207980552
Source: Nuggets
 

Guess you like

Origin blog.csdn.net/m0_50180963/article/details/115206328