这不是问题,它是特定于平台的行为,带有一点向后兼容性的味道。 HotSpot 的源代码中有两个有趣的文件:
-
globals_windows_x86.hpp http://hg.openjdk.java.net/hsx/hsx20/master/file/f0f676c5a2c6/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp设置运行时系统使用的 Windows 平台相关标志的默认值。
-
os_windows_x86.cpp http://hg.openjdk.java.net/hsx/hsx20/master/file/f0f676c5a2c6/src/os_cpu/windows_x86/vm/- 创建具有指定堆栈大小的线程
在 globals_windows_x86 HotSpot 中,为了使用系统默认值,将 ThreadStackSize 初始化为 0:
// Default stack size on Windows is determined by the executable (java.exe
// has a default value of 320K/1MB [32bit/64bit]). Depending on Windows version, changing
// ThreadStackSize to non-zero may have significant impact on memory usage.
// See comments in os_windows.cpp.
define_pd_global(intx, ThreadStackSize, 0); // 0 => use system default
define_pd_global(intx, VMThreadStackSize, 0); // 0 => use system default
在 os_windows_x86 中有一个解释,为什么 Windows 平台上堆栈大小为 0:
// Create the Win32 thread
//
// Contrary to what MSDN document says, "stack_size" in _beginthreadex()
// does not specify stack size. Instead, it specifies the size of
// initially committed space. The stack size is determined by
// PE header in the executable. If the committed "stack_size" is larger
// than default value in the PE header, the stack is rounded up to the
// nearest multiple of 1MB. For example if the launcher has default
// stack size of 320k, specifying any size less than 320k does not
// affect the actual stack size at all, it only affects the initial
// commitment. On the other hand, specifying 'stack_size' larger than
// default value may cause significant increase in memory usage, because
// not only the stack space will be rounded up to MB, but also the
// entire space is committed upfront.
//
// Finally Windows XP added a new flag 'STACK_SIZE_PARAM_IS_A_RESERVATION'
// for CreateThread() that can treat 'stack_size' as stack size. However we
// are not supposed to call CreateThread() directly according to MSDN
// document because JVM uses C runtime library. The good news is that the
// flag appears to work with _beginthredex() as well.
您还可以阅读MSDN文档 https://msdn.microsoft.com/en-us/library/aa246693(v=vs.60).aspx.
为什么 Windows 平台上的大小为零?这是将默认值传递给 WinAPI 的最简单方法,但 Java 主线程中存在问题http://bugs.java.com/view_bug.do?bug_id=4689767 http://bugs.java.com/view_bug.do?bug_id=4689767分辨率:
Windows:默认线程堆栈大小是从二进制文件中读取的
(java.exe);主线程堆栈就是以此大小创建的。
隐藏主要之间差异的替代解决方案
线程和其他线程的目的是避免在其中运行任何java字节码
主线程认为由于 JNI,一般来说这是不可能的。
在我们停止支持之前,它不会在 Windows 上修复
Win95/Win98/WinME
让我总结一下——ThreadStackSize
是一个内部属性,可以有任何默认值,例如 Windows 上的 0 以支持旧平台 (ME/98)。PrintFlagsFinal
它还提供没有任何保证的调试信息,因此在没有一定知识的情况下引用此信息是不正确的。从 1.7.0_45 开始,Hotpot 有一个很好的内部 VM 功能,称为“本机内存跟踪”(NMT) https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html
java -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -version
...
- Thread (reserved=14453KB, committed=14453KB)
(thread #14)
(stack: reserved=14392KB, committed=14392KB)
(malloc=44KB #76)
(arena=16KB #28)
您可以尝试将堆栈大小从默认值(在本例中为 1M,保留空间为 14453 KB)削减到较小的值-Xss256k
:
- Thread (reserved=10613KB, committed=10613KB)
(thread #14)
(stack: reserved=10552KB, committed=10552KB)
(malloc=44KB #76)
(arena=16KB #28)