As a Java debugger, one must focus on adopting the new and effective troubleshooting techniques. In this article, you’ll get to know what java remote debugging is, how to debug Java applications remotely, challenges in remote java applications, and real-time Java debugging techniques or tips that every Java developer must know.
Consider a situation where you need to fix a bug in a QA or UAT environment to which you do not have access as that environment is in a restricted network. How do you debug the issue in such a situation? The optimal solution is definitely remote debugging. Let us understand it better.
What is Java Remote Debugging
- Java Remote Debugging is the process of debugging a Java application that is already running on another server environment or a machine.
- Remote java debugging requires establishing a connection between the java debugger and the target system, unlike local debugging, where you debug an application that runs on the same device as your IDE.
- To understand this clearly, take a glance at the Java Platform Debugger Architecture (JPDA). JPDA is a multi-tier architecture that helps you in debugging a remote Java application.
- It consists of Java Debug Interface (JDI), the Java Debug Wire Protocol (JDWP), and the Java Virtual Machine Tool Interface (JVMTI) as shown within the high-level architecture diagram.
- As demonstrated above, the Java Debug Wire Protocol (JDWP) is one such protocol that contains information transmitted between the JVMTI and JDI. As soon as the connection is established, JDWP is assigned for interacting and giving instructions to the java debugger and debuggee (the application being debugged) when performing remote debugging.
- Whether the interface is related to the debugger or the debuggee, each has two activity forms. They are :
-
-
- Events (generated on the debuggee side)
- Requests (generated on the debugger side)
-
Java Debugging Techniques
Remote Java debugging is one of the techniques used frequently for troubleshooting and fixing the common types of bugs that Java developers run into. These include:
- Run-time errors: The errors that occur during a program’s execution and throw exceptions are usually termed run-time errors.
- Logic errors: Logic errors are different from run-time errors, where the exceptions are not generated. These bugs result in wrong or invalid outputs because of incorrect code implementation. Logic errors include memory leaks and incorrect behavior.
- Syntactical or compilation errors: Compilation errors are highly common but are easy to debug since they typically occur from typing mistakes.
- Threading errors: Threading errors are usually difficult to detect. This class of bugs constitutes the most essential percentage of Java errors that each debugging tool should address. These include deadlocks, synchronization errors, access violations, data race bugs, and more.
Why Use Remote Java Debugging
Java provides a Remote debugging feature using a listener binding mechanism. There are several reasons why developers may want to perform debugging on a remote java application. A few of them are as follows :
1. When the target system is unable to run a local debugger
Some situations are common for developers where the target system does not support a local debugger. For example, you might like to debug a java application remotely while debugging an embedded system where attaching a debugger is hard. It is the same in the case of distributed applications where replicating a bug is even more complicated, and logging is decentralized.
2. When local debugging events interfere with other applications running on the target system
This occurs when the target system is interactive. To avoid this problem, we use a remote debugger that directs its output to a remote screen. When debugging applications residing on dedicated machines such as web servers whose services cannot be shut down to allow local debugging, remote debugging comes in handy.
3. When you cannot access the application’s source files from the target system
When we cannot access the source files locally for debugging the application, you should establish a secure connection with the host system and launch a remote debugging session. Remote debugging is the best way to check into the bugs and understand how they occur when the visibility of a few bugs depends on the state of a running system.
In situations where the developer and target system are at different physical locations, remote Java debugging can be used. This results in a significant saving of time and cost.
There are many more reasons why development teams might want to debug a Java application remotely. And the best thing about Java remote debugging is that it allows developers to troubleshoot code and enhances collaboration among development teams.
How to Perform Remote Java Debugging
Several debugging platforms help developers in debugging a remote Java Application. These include Visual Studio, Eclipse, NetBeans and IntelliJ IDEA, and other regular IDEs that support java remote debugging capabilities. So firstly, choose a Java JVM that supports remote debugging and fits into your workflow.
Now, let’s have a look at debugging a java program using Eclipse.
- Go to the eclipse menu and select Run->Debug Configuration; it opens Debug Configuration setup.
- On the Debug configuration window, create a new “Remote Java Application” configuration.
- Select the project to be debugged and give it a Name.
- Select connection type, Socket Attach, or Socket Listen. If you want to attach the debugger to the running application, select Socket Attach, i.e., the application is running in Server mode.
- If you want the debugger to listen for JVM, connect, select Socket Listen, i.e., JVM is running in client mode, and debugger is running as a server.
- To run JVM on Server mode, start JVM in debug mode and then start the newly created debugger.
- And if Debugger has to be run on Server mode, then start the debugger and then start JVM.
In this way, you can debug any java application using any standard java debugger.
Java Configuration for Remote Debugging
There is a wide range of command-line arguments in JDWP that are used for debugging. One of them is Xdebug which is used to enable remote debugging and the other is Xrunjdwp which specifies JDWP implementation and connectivity details in the target VM. We must consider using -agentlib:jdwp instead of -Xdebug and -Xrunjdwp in Java V5 and subsequent releases.
Supplying the right configurations for transport, server, address, and suspend arguments is important while you invoke a remote java application. Here’s an example for you,
Java -agentlib:jdwp=transport=dt_socket,server=x,suspend=m,address=128.0.0.1:9000
As shown below, we have to use the runjdwp arguments for Java 5 and earlier versions
java -Xdebug
– Xrunjdwp_transport=dt_socket,server=x,suspend=m,address=7000
To allow remote launch, you need to pass remote debugging arguments to JVM and then configure your development environment. The configuration steps will depend on the tool you’re using.
Ensure that you provide the remote machine’s correct hostname or IP address when entering the configuration details for launching a remote debugging session. You’re all set for remote debugging once done with the configuration.
Challenges of Remote Java Debugging
There are a few challenges that are associated with remote Java debugging. They are:
- Performance degradation: Remote debugging mode affects an application’s or server’s performance because of disabling some JVM optimizations that provide a significant performance boost.
- Security implications: For the debugger to access the server, you need to open up specific ports while performing remote debugging.
This introduces a potential security risk to your system since malicious actions can take place, and debugging can also be initiated by bad actors who hit the server.
- Logging concerns: While debugging, the logging implementations write the log information of files within the application. Such solutions are not perfect because there’s a chance that you might lose recent log messages if an application crashes.
Getting diagnostic information from files can often be frustrating when log information is buried deep inside a directory that is difficult to access.
Best practices for Java Debugging
The following are the best practices that you can leverage to make your java debugging process faster and easier.
1. Hold Back, Do Not Overuse The Debugger
The debugger will help you to find errors in the java application but that shouldn’t be your first step. A lot can be done without using the debugger. So, hold back and try to analyze the cause of the bugs and fix them.
2. Use Conditional Breakpoints
The conditional breakpoint is the best if you are working with Java programming language and debugging your code in Eclipse IDE. To debug and detect root cause of the bugs, Eclipse allows you to use conditional breakpoints. Unlike a line breakpoint, a conditional breakpoint is a breakpoint that is defined with a condition and thread execution stops at the breakpoint when it’s condition is met.
3. Use Exception Breakpoints
In Eclipse, while debugging a Java program code, you are often encountered with a NullPointerException error and at such instances where you are not aware of the origin of the error, it can be frustrating. For such issues, an exception breakpoint is a form of the solution provided by the developers of Eclipse. NetBeans IDE also has this feature.
Now that you know this, for NullPointerException, you can simply use an exception breakpoint and on ArrayIndexOutofBoundException. You can easily set up an exception breakpoint from the breakpoint window.
4. Try To Recreate The Error
At times, debugging in java can be frustrating as you do not know the correct order of the events that cause the bugs. In such a case, recreating the error is the best option. So, understand how the system works, collect data, insert non-breaking breakpoints and logging statements and try to recreate the error. For this, you need to have a few hypotheses.
5. Test Your Hypotheses
To test your hypotheses, going for the unit test would be better than using a debugger. Unit tests are great because they help in reducing error possibilities and also verify the fix. Another advantage of using unit tests is that even if it fails, it helps you to disprove the hypothesis and another unit test is added to the list. This makes it robust.
However, a debugger can be used if there’s no chance to write unit tests.
6. Watchpoint
Watchpoint serves as the best feature of Eclipse IDE. It is a breakpoint that is set up on a field or a variable. Once the targeted field or variable is accessed or changed, the program’s execution will be stopped, enabling you to debug.
7. Stop assuming, start validating
Making assumptions while debugging is common for a java debugger. But, assuming the causes of bugs and the way in which the code would work might not be the best option. So, validating your assumptions using unit tests would make you more confident with the code.
8. Divide and conquer
When stuck, it’s always better to divide your system into parts and remove the part that does not seem like a cause for a bug. Also, eliminate the bugs that defend each other during this process. This method eases the process of finding the errors in the java application.
9. Step filtering
During the debugging process, sometimes the program’s control goes from one class to another class. Eventually, you are moved to the JDK classes like String or System or external libraries. Step filtering is used when you do not want to move to the external libraries or JDK classes. Step filtering can also be used to filter out the JDK classes. During the process of debugging, this feature will assist you in skipping some particular packages.
An Effective Approach to Remote Java Debugging
Firstly, you must collect data to figure out what is causing the bug and to debug Java applications properly. However, when debugging a Java application remotely it can be difficult and can often come with many performance caveats. Using an advanced debugger would be a better remote debugging option. Streamlining the remote Java debugging process can be performed in multiple ways, but the most notable ones are here.
1. Detail Formatter
Sometimes, while you debug and inspect variables/objects, you might come across some textual representations of objects that are not meaningful. For example, Implementing the .toString() method just for debugging purposes might not be a great idea. Instead, a detail formatter can be set up to look after the textual representation of your object.
To get there right-click on the variable in the Variables view, then select New Detail Formatter.
2. Logical Structure
Here you’ll visualize the magic that a single click will create. Enable the Logic Structure in your Variables view, to get the “contents” and “structure” of the objects more understandably and clearly.
3. Drop To Frame
“Drop To Frame” can be used when you want to jump back in your stack and then start debugging from a particular point. For example, your application stopped at your breakpoint and you want to go back, then Drop To Frame can be used.
4. Changing Variable values
The Variables View helps you in displaying values, editing them, and perform more such operations.
5. Inspect And Watch
Inspect is similar to Variables View, here you can unfold and inspect the various values of the object. On the other hand, watch enables you to observe the changes of a specific Object.
6. Shortcuts
It can be frustrating to constantly switch between keyboard and mouse. Here are a few shortcuts that will come in handy for you and speed up your work
F5 – Step Into
F6 – Step Over
F7 – Step Return
F8 – Run until next breakpoint is reached
7. Breakpoints
- Basic Breakpoints
You can create a breakpoint by double-clicking on the left side of a line of code. This will halt the execution at that point so that you can analyze the state and debug.
- Exception Breakpoints
Sometimes it’s difficult to find out where the exception has occurred. In such instances, creating a global breakpoint can be helpful. You can find it in the Breakpoints view of the Debug perspective.
- Conditional Breakpoints
To speed up the debugging process you can add a condition. By doing so, the breakpoint will only stop your application if the condition is true. To get there, right-click on your breakpoint, and then, Breakpoint Properties.
Conclusion
Java remote debugging always comes in handy, either while creating a new product or maintaining an already developed application. Remote debugging is a solution to most of the debugging problems that exist in modern software architecture. We all know, bugs are an inevitable part of every programmer’s life.
Remote debugging is an art and science that you can only excel by constant learning and practice like any other aspect of software development. We suggest you save this article and implement all the remote java debugging tips. These tips guide you to streamline your debugging processes. The essential point to be noted is to choose a tool that gives you the desired speed and ease in your development workflow.
In addition to streamlining remote debugging processes in development and QA environments, you also need tools to perform similar activities in production environment. For such purposes use Seagence. Seagence uncovers all production defects with root cause in real-time and eliminates the need for debugging.
All you need to do is to attach a lightweight runtime java agent when you start your application. That’s it. Whenever a defect occurs in your production, you will get an alert directly to your inbox. Upon opening the alert, you will find the failing functionality and the root cause exception stack trace. You will find more debug information, if needed, on SeagenceWeb.
Sounds great right? Then why not try using the Seagence Defect Monitoring tool.