Build and run a Linux/x86 slowdebug binary as follows:
bin/java -client -XX:NativeMemoryTracking=detail -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics -version
You will see some NMT backtraces that include NativeCallStack::NativeCallStack() at the top, such as the following:
[0x00007f7da5e0ac94] NativeCallStack::NativeCallStack(int, bool)+0x68
[0x00007f7da5a87868] GenericGrowableArray::raw_allocate(int)+0xe2
[0x00007f7da5a243bc] GrowableArray<PausePhase>::GrowableArray(int, bool, MemoryType)+0x68
[0x00007f7da5a21075] TimePartitions::TimePartitions()+0x85
(malloc=3KB #5)
NMT is suppose to skip frames at the top related to generating the backtrace. This includes skipping NativeCallStack::NativeCallStack(). However, for x86 slowdebug builds, not enough frames are skipped. This is because _get_previous_fp() in os_linux_x86.cpp is not being inlined, and this is not being accounted for.
Note that os::get_native_stack() in os_posix.cpp does attempt to skip extra frame(s) for debug builds:
#ifdef _NMT_NOINLINE_
toSkip++;
#endif
However, this frame skip is to take into account that the call to os::get_native_stack() from NativeCallStack::NativeCallStack is not done as a tail call for slowdebug builds. Adding 1 more to toSkip will not work for ARM and other platforms which don't have _get_previous_fp(), and therefore don't get this extra frame in slowdebug builds. The fix needs to be in _get_previous_fp(), possibly just having it skip an extra frame for slowdebug builds.
bin/java -client -XX:NativeMemoryTracking=detail -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics -version
You will see some NMT backtraces that include NativeCallStack::NativeCallStack() at the top, such as the following:
[0x00007f7da5e0ac94] NativeCallStack::NativeCallStack(int, bool)+0x68
[0x00007f7da5a87868] GenericGrowableArray::raw_allocate(int)+0xe2
[0x00007f7da5a243bc] GrowableArray<PausePhase>::GrowableArray(int, bool, MemoryType)+0x68
[0x00007f7da5a21075] TimePartitions::TimePartitions()+0x85
(malloc=3KB #5)
NMT is suppose to skip frames at the top related to generating the backtrace. This includes skipping NativeCallStack::NativeCallStack(). However, for x86 slowdebug builds, not enough frames are skipped. This is because _get_previous_fp() in os_linux_x86.cpp is not being inlined, and this is not being accounted for.
Note that os::get_native_stack() in os_posix.cpp does attempt to skip extra frame(s) for debug builds:
#ifdef _NMT_NOINLINE_
toSkip++;
#endif
However, this frame skip is to take into account that the call to os::get_native_stack() from NativeCallStack::NativeCallStack is not done as a tail call for slowdebug builds. Adding 1 more to toSkip will not work for ARM and other platforms which don't have _get_previous_fp(), and therefore don't get this extra frame in slowdebug builds. The fix needs to be in _get_previous_fp(), possibly just having it skip an extra frame for slowdebug builds.
- relates to
-
JDK-8163899 NMT frame skipping code is fragile
-
- Closed
-
-
JDK-8163900 os::current_frame has a misleading name
-
- Closed
-
-
JDK-8163011 AArch64: NMT detail stack trace cleanup
-
- Resolved
-