I finally found the answer from the JDK source code.
Get the source code:
hg clone http://hg.openjdk.java.net/jdk8/jdk8/hotspot/
According to the JDK documentation, Xss value can change the Java Thread Stack Size. But how does the argument work? Here is the code :
HANDLE thread_handle =
(HANDLE)_beginthreadex(NULL,
(unsigned)stack_size,
(unsigned (__stdcall *)(void*)) java_start,
thread,
CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
&thread_id);
Xss is assigned to stack_size, which is used to allocate memory for the thread stack.
But what if you set nothing? In os_windows.cpp, see the following paragraph:
// 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.
If you do not set Xss value, the default stack size depends on the PE file(java.exe). If you run a 32-bit Java app, the default stack size is 320K. If you run a 64-bit Java app, the default stack size is 1024K.
We can use following source code to verify the stack size:
#include <windows.h>
typedef u_char* address;
address os::current_stack_base() {
MEMORY_BASIC_INFORMATION minfo;
address stack_bottom;
size_t stack_size;
VirtualQuery(&minfo, &minfo, sizeof(minfo));
stack_bottom = (address)minfo.AllocationBase;
stack_size = minfo.RegionSize;
// Add up the sizes of all the regions with the same
// AllocationBase.
while( 1 )
{
VirtualQuery(stack_bottom+stack_size, &minfo, sizeof(minfo));
if ( stack_bottom == (address)minfo.AllocationBase )
stack_size += minfo.RegionSize;
else
break;
}
#ifdef _M_IA64
// IA64 has memory and register stacks
//
// This is the stack layout you get on NT/IA64 if you specify 1MB stack limit
// at thread creation (1MB backing store growing upwards, 1MB memory stack
// growing downwards, 2MB summed up)
//
// ...
// ------- top of stack (high address) -----
// |
// | 1MB
// | Backing Store (Register Stack)
// |
// | / \
// | |
// | |
// | |
// ------------------------ stack base -----
// | 1MB
// | Memory Stack
// |
// | |
// | |
// | |
// | \ /
// |
// ----- bottom of stack (low address) -----
// ...
stack_size = stack_size / 2;
#endif
return stack_bottom + stack_size;
}