I currently hava a running Java application, which has a bug. I don't know how to fully reproduce it and it didn't happen for weeks until now. When it occurs one times, I can reproduce it over and over again easily until I restart the application. The bug causes a StackOverflowError because of a recursion and I don't know how this happens. The printed stacktrace of the StackOverflowError isn't helpful because it contains only the repeating part, but not the more insteresting initial part, because the JVM has a limit for stacktrace entries. The -XX:MaxJavaStackTraceDepth=... can be used to set this limit as explained here. The problem is that I think I have to restart my application in order to add this flag. But if I do so, I won't be able to reproduce the bug anymore. Is there any solution how I can get the full stacktrace or set this flag without restarting the application?
            Asked
            
        
        
            Active
            
        
            Viewed 613 times
        
    1
            
            
        
        stonar96
        
- 1,359
 - 2
 - 11
 - 39
 
- 
                    2You can attach a debugger to the running application to inspect the entire stack. – nanofarad Dec 10 '20 at 17:57
 - 
                    What's wrong with the question? Why do people downvote this? – stonar96 Dec 10 '20 at 18:01
 - 
                    1I don't know, as I didn't downvote (but I think your comment got routed back to me as a ping because nobody else commented). I think it's a reasonable question, and I gave a suggestion, but I don't have the time to write a full answer to high quality at the moment. – nanofarad Dec 10 '20 at 18:05
 - 
                    1Sorry my comment was not targeting you but it was rather a general question what I can improve. I will try to attach a debugger, thanks. – stonar96 Dec 10 '20 at 18:12
 - 
                    It seems like this is not possible. According to https://docs.oracle.com/javase/7/docs/technotes/tools/windows/jdb.html a VM that is to be debugged with jdb must be started with the options `-agentlib:jdwp=transport=dt_shmem,server=y,suspend=n` – stonar96 Dec 10 '20 at 18:31
 - 
                    Ack - this is part of the reason why I was remiss to write a full answer. – nanofarad Dec 10 '20 at 18:58
 
1 Answers
4
            I know at least two solutions.
Create HotSpot Serviceability Agent tool to find the address of
MaxJavaStackTraceDepthvariable in memory, and then update the memory of the process using OS-specific mechanism.Attach a JVM TI agent that intercepts
StackOverflowErrorsand prints a stack trace right from the agent.
Here is the code for the first solution (as it is presumably shorter):
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
import java.io.IOException;
import java.io.RandomAccessFile;
public class ChangeVMFlag extends Tool {
    private static String pid;
    @Override
    public void run() {
        Address addr = VM.getVM().getCommandLineFlag("MaxJavaStackTraceDepth").getAddress();
        long addrValue = VM.getVM().getDebugger().getAddressValue(addr);
        try (RandomAccessFile raf = new RandomAccessFile("/proc/" + pid + "/mem", "rw")) {
            raf.seek(addrValue);
            raf.writeInt(Integer.reverseBytes(1_000_000));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        pid = args[0];
        new ChangeVMFlag().execute(new String[]{pid});
    }
}
This tool changes the value of MaxJavaStackTraceDepth in the target process to 1 million.
Note: it uses Linux-specific /proc API to write into the target process' memory. Other OSes have different interfaces.
How to run
On JDK 8
java -cp .:$JAVA_HOME/lib/sa-jdi.jar ChangeVMFlag <pid>
On JDK 9+
java --add-modules=jdk.hotspot.agent \
     --add-exports jdk.hotspot.agent/sun.jvm.hotspot.tools=ALL-UNNAMED \
     --add-exports jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED \
     --add-exports jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED \
     ChangeVMFlag <pid>
        apangin
        
- 92,924
 - 10
 - 193
 - 247