JDK-4689767 : main thread stack size not the same as other threads on all platforms (-Xss)
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 1.4.0,1.4.1,1.4.1_02,1.4.2_03,5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS:
    generic,linux,windows_nt,windows_2000 generic,linux,windows_nt,windows_2000
  • CPU: generic,x86
  • Submitted: 2002-05-22
  • Updated: 2005-08-29
  • Resolved: 2005-08-29
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
The stack for the main thread is created by the o/s when the process is
created; the vm cannot later increase the size of this stack.  The stack
sizes for other java threads created by the vm are (mostly) controlled
by the vm, and use the -Xss<N> value or a default.  (The 'mostly' is
because of operating system eccentricities.)

The different stack sizes for the main thread vs. other threads means
that some (typically recursive) routines may be able to run in one
thread, but not in another.  It also means that the -Xss<N> argument
to set the thread stack size does not apply to all threads, at least
on some platforms.  This asymmetry should be eliminated.

EVALUATION I'm fixing this for mustang under a different bugid (6316197). The basic idea is to let Java launcher create a new thread and invoke JVM from the new thread. Contrary to earlier evaluation, the cost of creating a new thread is negligible in startups (previous evaluation is probably referring to a VM only solution which is hard to implement without breaking existing applications that embed JVM, 6316197 is to modify standard Java launcher). Please see also 6316878 which deals with Windows stack size problem. With the fix for 6316197, main thread stack size is controlled by -Xss the same way as other Java thread, with some limitations due to OS: + Windows before XP will have 1MB granularity, and the entire stack is committed upfront. Since Windows XP, the thread stack size will have granularity of 64KB, and stack pages are committed on demand. + Old Linux pthread library (LinuxThreads) does not allow application to create threads with stack size larger than ulimit -s value. This is not a problem with NPTL. I'm closing this bug as a duplicate of 6316197.

EVALUATION ###@###.### 2002-05-22 The current state of affairs on the different operating systems: Solaris: the size of the main thread stack comes from the ulimit. The main thread stack is artificially reduced by the vm to the -Xss value (or to the default size, which is 256k for 32-bit intel, 512K for 32-bit sparc, 1M for 64-bit sparc) by installing guard pages. So the -Xss value does affect the main thread on solaris, by reducing it. This behavior has not yet been adopted on linux (but likely will be, according to comments in bug 4678676). Linux: On RH linux 6.x and 7.0, the threads library only supports stacks of exactly 2MB, no larger, no smaller. On RH 7.1 and later, 'floating' stacks of variable size are supported. As in solaris, the main thread stack size comes from the ulimit. However, even on 7.1 and later, the vm limits the max stack size for *all* threads, including the main thread, to 2MB to work around a bug in the pthreads library (smaller stacks are allowed). The pthreads bug causes a SEGV if any part of the stack > 2MB is touched; it may be fixed in RH7.3, but the vm has to support older versions. Windows: the default thread stack size is read from the binary (java.exe); the main thread stack is created with this size. Currently (1.4.1beta) the j2se build sets this to 256k. For threads created by the vm, beginthreadex is called to create the threads, and the -Xss value is passed as the desired stack size. Note that on NT4.0 SP6 (win/9x, 2000 and XP are likely similar, but have not been tested), the o/s rounds up thread stack sizes using very coarse granularity: if the requested size is less than than the default stack size by 1 K or more, the stack size is rounded up to the default; otherwise, the stack size is rounded up to a multiple of 1 MB. ------------------------------- Linux should be made similar to solaris, within the limitations of thread library (e.g., the max size on linux would still be 2MB). The vm should issue a warning that the max stack size is being truncate to 2MB when the -Xss value is more than 2MB. On windows, could make the default stack size large and then reduce it with guard pages as on solaris. But this is tricky on windows because a) on windows 95/98/ME, the operating system does not support re-protecting pages on the stack, or changing the protection on pages in the middle of the stack. (These operations are allowed in windows NT4/2000/XP.) b) the default stack size would be used by any threads created by native (JNI) code. If an application created large numbers of threads from within JNI native methods, the address ranges reserved for the stacks could exhaust the address space. This is likely a very rare occurrence. Note that (b) does not apply to a native app which embeds the vm, since the binary (.exe) which starts the process sets the default stack size. An alternative solution that hides the differences between the main thread and other threads is to avoid running any java bytecodes in the main thread. This was looked at during 1.3.1 development; believe it is not possible in general because of JNI. -------------- ###@###.### 08/14/2003 This issue is already fixed in Solaris/Linux. It will NOT be fixed on windows till we stop supporting supporting Win95/Win98/WinME, i.e. not this year. The current Status of this issue on all 3 platforms that we support: A) Solaris: Works as expected. The size of the main thread stack comes from the ulimit. The main thread stack is artificially reduced by the vm to the -Xss value (or to the default size) by installing guard pages. So the -Xss value does affect the main thread on solaris, by reducing it. B) Linux: Works now. Fixed by Hui Huang as part of the bug fix 4678676. Main thread stack is artificially reduced to whatever value specified by -Xss. If -Xss is not specified, main thread stack size is the default size defined by ulimit -s. C) Windows: Does not work and is the only platform that needs to be fixed. The main thread stack is created with default thread stack size (256K) that is read from the binary (java.exe); For threads created by the VM, beginthreadex is called to create the threads, and the -Xss value is passed as the desired stack size. Some of the suggestions proposed for the windows fix are: 1) Use editbin utility to change the stack size. editbin changes the default thread stack size for all threads started by that .exe. I believe hotspot on windows uses the default stack size for all threads created by the vm unless -Xss is passed on the command line, so editbin won't solve the problem for the main thread. 2) Main thread starts a new thread with right size. Peter Kessler: I thought the "real" fix was to have the main thread start a new thread that had the right size and then either exit the main thread or have it block waiting for the VM to otherwise exit. The idea was to do only a bounded amount of work in the main thread. Maybe that idea has been abandoned. It's been a while since I thought about this problem. I would defer to the runtime folks on this one. James McIlree looked at doing that and decided it was not feasible. The big showstopper was the start up regression. 3) John Coomes: There may be some windows magic that can be done, but I'm not aware of it. So I think we're stuck with this situation on windows until we drop support for win95, win98 and winME. NT4, win2k and winXP all allow the stack protections to be changed, so there is some hope on those platforms of using the same technique that we now use on solaris and linux. Would have to change the default stack size in the binary to make it large, then have the vm use a smaller stack size for other threads. This means that threads created by jni would get large stacks, but that may be ok. 4) Dave Dice: That's a tough problem. I've attached some email dialog that's slightly related. As John says, the default stack size for threads created by the process is embedded in the PE executable (it can be set by editbin, the linker, etc.). Unfortunately that's not really appropriate for the JVM. Other than explicit stack-switching at VM attach time I haven't come up with a reasonable solution. <Please see below Email that Dave is referring to> Date: Fri, 8 Nov 2002 17:38:38 -0500 (EST) From: ###@###.### To: ###@###.### Subject: RE: JPSE jdk1.3.1._07 4765019 Code Review Request, due by 11/12/02_3:40_PM Cc: ###@###.### Yumin, Thanks for the information you sent out wednesday. Remarks: 1. I wonder if the reserve_memory-release_memory pair in os::create_thread is really necessary? It strikes me as a work-around that may no longer be needed. Postulating: _beginthreadex would fail horribly and _not return under some low-memory conditions. The reserve-release pair was a somewhat feeble attempt to avoid that failure on some ancient version of windows. We should look into who put the code in the system and consider taking it out, if possible. It may be vestigal. 2. Despite the comments from Oracle and Microsoft I don't think that passing a stack_size of 0 into _beginthreadex is wise. (using 0 is generally a good idea for monolithic apps, but the JVM is a specific exception). First, we're starting to see executables that load some other service that in turn load in the JVM. In this case the reserve/commit sizes encoded in the original PE executable header may not be appropriate for the JVM. I'd like to make sure that users (or, for embedded apps, the code that launches the JVM) has the option to specify stack size. The original builder of the EXE may not have even known that it'd eventually be used with a JVM loaded in its address space. Also, we _do want to commit some stack. If the system runs low on memory (we've over-commited) and the JVM hits a demand-zero fill fault on a stack page I believe that windows will clobber the thread/process. (I know that's true on solaris, and it used to be true on windows, but I haven't verified it since NT 3.5). This kind of abrupt failure isn't appropriate for enterprise applications. In Tiger, we're considering adding a flag to force the entire stack to be reserved. This will prevent the abrupt shutdown problem, but, because of the commit charges, it means we'll be able to run fewer threads|JVMs|processes concurrently (IE, the flag will prevent over-commit). We'll should consider looking into this for Tiger. 3. The targetted work-around you proposed is fine for 1.3.X, but beware that it might increase the odds of abrupt JVM failure in low-memory conditions. (abrupt means the java code wouldn't get a chance to catch exceptions and recover). We need to think about whether we'd want to roll that fix forward into 1.4.2/1.5. Thanks for the fix! Regards, Dave Karen: I've CC:ed you as we'll likely want to address this issue in Tiger. See msdn.microsoft.com/library/en-us/dllproc/base/thread_stack_size.asp?frame=true There's some confusion in HS about reserved vs commited stack size that we should clear up.