Skip to content

Commit 0735c8a

Browse files
David Holmesstefank
andcommitted
8318302: ThreadCountLimit.java failed with "Native memory allocation (mprotect) failed to protect 16384 bytes for memory to guard stack pages"
Co-authored-by: Stefan Karlsson <[email protected]> Reviewed-by: shade, stefank
1 parent 5fa2bdc commit 0735c8a

File tree

2 files changed

+45
-16
lines changed

2 files changed

+45
-16
lines changed

src/hotspot/share/utilities/vmError.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, bool pri
489489
static void print_oom_reasons(outputStream* st) {
490490
st->print_cr("# Possible reasons:");
491491
st->print_cr("# The system is out of physical RAM or swap space");
492+
#ifdef LINUX
493+
st->print_cr("# This process has exceeded the maximum number of memory mappings (check below");
494+
st->print_cr("# for `/proc/sys/vm/max_map_count` and `Total number of mappings`)");
495+
#endif
492496
if (UseCompressedOops) {
493497
st->print_cr("# This process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap");
494498
}

test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* @summary Stress test that reaches the process limit for thread count, or time limit.
2727
* @requires os.family != "aix"
2828
* @key stress
29+
* @library /test/lib
2930
* @run main/othervm -Xmx1g ThreadCountLimit
3031
*/
3132

@@ -34,12 +35,17 @@
3435
* @summary Stress test that reaches the process limit for thread count, or time limit.
3536
* @requires os.family == "aix"
3637
* @key stress
38+
* @library /test/lib
3739
* @run main/othervm -Xmx1g -XX:MaxExpectedDataSegmentSize=16g ThreadCountLimit
3840
*/
3941

4042
import java.util.concurrent.CountDownLatch;
4143
import java.util.ArrayList;
4244

45+
import jdk.test.lib.Platform;
46+
import jdk.test.lib.process.OutputAnalyzer;
47+
import jdk.test.lib.process.ProcessTools;
48+
4349
public class ThreadCountLimit {
4450

4551
static final int TIME_LIMIT_MS = 5000; // Create as many threads as possible in 5 sec
@@ -61,21 +67,42 @@ public void run() {
6167
}
6268
}
6369

64-
public static void main(String[] args) {
70+
public static void main(String[] args) throws Exception {
71+
if (args.length == 0) {
72+
// Called from the driver process so exec a new JVM on Linux.
73+
if (Platform.isLinux()) {
74+
// On Linux this test sometimes hits the limit for the maximum number of memory mappings,
75+
// which leads to various other failure modes. Run this test with a limit on how many
76+
// threads the process is allowed to create, so we hit that limit first.
77+
78+
final String ULIMIT_CMD = "ulimit -u 4096";
79+
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(ThreadCountLimit.class.getName());
80+
String javaCmd = ProcessTools.getCommandLine(pb);
81+
// Relaunch the test with args.length > 0, and the ulimit set
82+
ProcessTools.executeCommand("bash", "-c", ULIMIT_CMD + " && " + javaCmd + " dummy")
83+
.shouldHaveExitValue(0);
84+
} else {
85+
// Not Linux so run directly.
86+
test();
87+
}
88+
} else {
89+
// This is the exec'd process so run directly.
90+
test();
91+
}
92+
}
93+
94+
static void test() {
6595
CountDownLatch startSignal = new CountDownLatch(1);
6696
ArrayList<Worker> workers = new ArrayList<Worker>();
6797

68-
boolean reachedTimeLimit = false;
6998
boolean reachedNativeOOM = false;
70-
int countAtTimeLimit = -1;
71-
int countAtNativeOOM = -1;
7299

73100
// This is dangerous loop: it depletes system resources,
74101
// so doing additional things there that may end up allocating
75102
// Java/native memory risks failing the VM prematurely.
76103
// Avoid doing unnecessary calls, printouts, etc.
77104

78-
int count = 1;
105+
int count = 0;
79106
long start = System.currentTimeMillis();
80107
try {
81108
while (true) {
@@ -86,16 +113,15 @@ public static void main(String[] args) {
86113

87114
long end = System.currentTimeMillis();
88115
if ((end - start) > TIME_LIMIT_MS) {
89-
reachedTimeLimit = true;
90-
countAtTimeLimit = count;
116+
// Windows always gets here, but we also get here if
117+
// ulimit is set high enough.
91118
break;
92119
}
93120
}
94121
} catch (OutOfMemoryError e) {
95122
if (e.getMessage().contains("unable to create native thread")) {
96-
// Linux, macOS path
123+
// Linux, macOS path if we hit ulimit
97124
reachedNativeOOM = true;
98-
countAtNativeOOM = count;
99125
} else {
100126
throw e;
101127
}
@@ -113,13 +139,12 @@ public static void main(String[] args) {
113139

114140
// Now that all threads have joined, we are away from dangerous
115141
// VM state and have enough memory to perform any other things.
116-
if (reachedTimeLimit) {
117-
// Windows path or a system with very large ulimit
118-
System.out.println("INFO: reached the time limit " + TIME_LIMIT_MS +
119-
" ms, with " + countAtTimeLimit + " threads created");
120-
} else if (reachedNativeOOM) {
121-
System.out.println("INFO: reached this process thread count limit with " +
122-
countAtNativeOOM + " threads created");
142+
if (reachedNativeOOM) {
143+
System.out.println("INFO: reached this process thread count limit with " +
144+
count + " threads created");
145+
} else {
146+
System.out.println("INFO: reached the time limit " + TIME_LIMIT_MS +
147+
" ms, with " + count + " threads created");
123148
}
124149
}
125150
}

0 commit comments

Comments
 (0)