2012년 12월 27일 목요일

[TechNote] Diagnosing a java.lang.StackOverflowError

Diagnosing a java.lang.StackOverflowError 

 

Problem(Abstract)

Stack Overflow errors are due to recursive looping either in the application code or the java generated JIT code. It should be noted that each thread (except on Solaris and HP-UX) has a default java stack and native stack. In cases where the defaults are not sufficient, it could result in java stack overflow or native stack issues.

Symptom

A stack overflow can result from:

However, the majority of stack overflow issues are masked by Out of Memory exceptions. By resolving the memory constraints, the stack overflow can be resolved.


Cause

When a stack overflow occurs, the amount of stack space required by the program exceeds what is configured for the stack in the Java™ Virtual Machine (JVM) process. A stack overflow is not always caused by a problem in a Java program. Some programs require stacks that are larger than the default size; for example, a graphics-intensive Java program can require a larger stack.

Diagnosing the problem

Look for either Out of Memory messages or java.lang.StackOverflow in the server logs. The process may continue to run after either of these messages are seen.

If a crash did occur, a javacore should have generated on IBM SDK. You will either see the signal as SIGSEGV, SIGILL, SIGABRT, or SIGBUS. Usually the current thread will indicate the following

pending=java.lang.StackOverflowError

Resolving the problem

Explanations and Solutions
Detailed Configuration Options


Explanations and Solutions


Infinite Recursion
If an application is performing recursion, the maximum stack size can easily be reached and a Stack Overflow exception is thrown. The thread stack has a limited size and eventually its space will run out as the thread stack grows without bounds.

Some traits of recursion:
- Large thread stacks that appear to repeat
- An infinite loop that continuously spawns off threads
- Very large XML documents loaded into the Document Object Model (DOM)
- JSP or servlets calling itself (usually by executing forward or include to itself)
- Repeated calls in native functions

Increasing the thread stack size allows for larger stacks. However if the recursion continues to trigger a stack overflow, the next step is to identify what code is causing the recursion from javacores, thread dumps, or even system core files.

A thread stack that indicates it's too large to display can be an indicator of stack overflow. This is especially true if the stack appears to repeat (such as recursive method calls).

JIT/HotSpot Compiled Code

The JIT/HotSpot compiler (JIT) is designed to speed up the JVM execution times by compiling method calls. This can speed up execution time, but as more aggressive optimizations are used, this can inadvertently cause recursion, resulting in stack overflow or crash. The documents linked below explain how to debug JIT and HotSpot compiler issues:


Depleted Native Stack
It is almost guaranteed that a crash will occur if the native stack runs out of space. System cores can be used to identify long and possibly recursively looping native thread stacks.

To resolve, increase the native stack size to accommodate the recursive native calls; however, identifying the native calls that are made will help determine which code is causing the stack overflow.






Detailed Configuration Options


Adjusting the Stack Sizes (Xss and Xmso) options
If this does not work, you can adjust the stack sizes at both the JVM and native level. Doubling the stack size is suggested as a first step; however, every thread that the JVM creates will consume memory. Be careful to not exhaust your physical memory resources.

For every Java thread, there are two stacks that are utilized. One is for Java code for method calls, and the other is for native C code (on Solaris and HP-UX, only the native stack is utilized). These are adjustable and can be raised to provide more room on the stacks to prevent an overflow.

    Native Stack Size (-Xss)
    This parameter adjusts the size for the native stack. Java code uses this to process calls made into native libraries, such as JIT or JNI calls. If there is an abundance of calls made on the native stack, adjust the native stack size using this generic JVM argument:

    -Xss<size>
    Where <size> has the format, nn[k|m|g|K|M|G], such as -Xss512K



    On Solaris and HP-UX systems which use the HotSpot JVM, there is no distinction between native and thread stack sizes. This is the only configurable value for all stack sizes; however, on HP-UX systems, there is another argument used to control stack size of the main method.

    -XX:MainThreadStackSize=<size>


    While the -Xss controls the stack size of all threads in native memory, -XX:MainThreadStackSize controls the size of the main thread. The main thread's native size will be set to whichever value is higher.



    Minimum Thread Stack Size (-Xiss)
    This is only for distributed platforms (AIX, Linux, Windows)

    Adjusts the minimum stack size that the JVM will start with. The default for all distributed platforms is 2KB. In most cases, you will not need to change this option.

    -Xiss<size>
    Where <size> has the format, nn[k|m|g|K|M|G], such as -Xiss2K


    Maximum Thread Stack Size (-Xoss | -Xmso)
    This is only for distributed platforms (AIX, Linux, Windows)
    -Xoss is deprecated in later versions of the IBM SDK, and has been replaced by -Xmso.

    This parameter controls the stack size of Java method calls (non-native) to track the state of variables. If you find looping code or large stacks that are all calling Java methods and do not make native calls, try raising the stack size by using the generic JVM argument below:

    -Xmso<size>
    Where <size> has the format, nn[k|m|g|K|M|G], such as -Xmso512K.


Default Values
This is a chart of default sizes for the various stack size arguments. This is subject to change due to upgrades of the SDK.


Value

AIX

Linux

Windows

Solaris

HP-UX

Minimum Thread Stack Size

2KB

2KB

2KB

Not Adjustable

Not Adjustable

Maximum Thread Stack Size

256KB (32-bit)
512KB (64-bit)

256KB (32-bit)
512KB (64-bit)

256KB (32-bit)
512KB (64-bit)

Not Adjustable

Not Adjustable

Native Stack Size

256KB

256KB

32KB (32-bit)
256KB (64-bit)

512KB (32-bit)
1024KB (64-bit)

64KB (PA-RISC)
1024KB (Itanium)




Examples of Stack Overflow

Server Logs
These logs may contain references to StackOverflow, alongside other messages. Thread stacks may accompany these messages, indicating if there is a recursive call.
    SystemOut.log example[3/14/15 3:14:15:926 CST] 31415926 BaseMap W CWOBJ0006W: An exception occurred:
    com.ibm.websphere.objectgrid.ObjectGridRuntimeException: java.lang.StackOverflowError
    <<Thread stack may follow this message>>



    SystemErr.log example[3/14/15 3:14:15:926 PST] 31415926 SystemErr R Caused by: java.lang.StackOverflowError
    at java.util.Hashtable.get(Hashtable.java:461)
    at com.ibm.ws.webcontainer.srt.SRTServletRequest.getParameter(SRTServletRequest.java:1257)
    at psdi.webclient.system.session.WebClientSession.applySkin(WebClientSession.java:295)
    at psdi.webclient.system.controller.AppInstance.render(AppInstance.java:1177)
    at psdi.webclient.system.controller.AppInstance.render(AppInstance.java:1213)
    at psdi.webclient.system.controller.AppInstance.render(AppInstance.java:1213)
    ...
Javacore

In javacores, look for "StackOverflowError" in the thread name entry:
3XMTHREADINFO "ORB.thread.pool : 19" (TID:10167F78, sys_thread_t:E072BCE0, state:R, native ID:E06BEBA0) prio=5: pending=java.lang.StackOverflowError

System Dump (processed with jextract and DTFJ Dump Analyzer)

Look for this message near the end of a very large stack. This particular example had 1000 recursively called entries.
Java stack frames dump is too long: <analyzererror>

댓글 없음:

댓글 쓰기