序
本文主要研究一下 jvm 的 Stack Memory
Virtual Machine Stack
每个 jvm 线程都有一个私有的 Virtual Machine Stack,它在线程同时被创建
该 stack 主要用于存储 frames,即所谓的 stack frames
每个方法在执行的时候都会创建一个 stack frame,用于存储方法的局部变量、返回值、Operand stack 等
Stack Memory
Stack Memory 是执行线程时所使用的内存,他们包含了方法用到的一些短生命周期的 values 及 heap 中 objects 的引用
Stack Memory 是按照 LIFO (Last-In-First-Out)的顺序被引用的,每当一个方法被调用,都会在 stack memory 中创建一块区域用于保存原始类型的值及 heap 中 objects 的引用;当方法执行结束时,这块区域就被释放可以被下一个方法使用;相对于 heap memory 来说,stack memory 是非常小的一块。通过 -Xss 或者 -XX:ThreadStackSize 可以指定 stack memory 的大小
当一个线程所需的 stack size 超过了设定的大小是,jvm 会抛出 StackOverflowError;而当系统没有足够内存可以供 jvm 创建一个新线程时,jvm 会抛出 OutOfMemoryError
StackOverflowError 实例
/**
* -Xss144k
*/
@Test
public void testStackOverflow(){
recursiveInvoke();
}
public void recursiveInvoke(){
String uuid = UUID.randomUUID().toString();
recursiveInvoke();
}
异常输出如下:
java.lang.StackOverflowError
at java.base/sun.security.provider.ByteArrayAccess.b2iBig64(ByteArrayAccess.java:263)
at java.base/sun.security.provider.SHA.implCompressCheck(SHA.java:139)
at java.base/sun.security.provider.SHA.implCompress(SHA.java:128)
at java.base/sun.security.provider.SHA.implDigest(SHA.java:109)
at java.base/sun.security.provider.DigestBase.engineDigest(DigestBase.java:210)
at java.base/sun.security.provider.DigestBase.engineDigest(DigestBase.java:189)
at java.base/java.security.MessageDigest$Delegate.engineDigest(MessageDigest.java:629)
at java.base/java.security.MessageDigest.digest(MessageDigest.java:385)
at java.base/sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:245)
at java.base/sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:535)
at java.base/sun.security.provider.NativePRNG$NonBlocking.engineNextBytes(NativePRNG.java:318)
at java.base/java.security.SecureRandom.nextBytes(SecureRandom.java:741)
at java.base/java.util.UUID.randomUUID(UUID.java:150)
at com.example.VMStackTest.recursiveInvoke(VMStackTest.java:21)
Xss 越大,每个线程的大小就越大,占用的内存越多,能创建的线程就越少;Xss 越小,则递归的深度越小,容易出现栈溢出 java.lang.StackOverflowError。减少局部变量的声明,可以节省栈帧大小,增加调用深度。
OOMKilled 实例
代码实例
public void createThreadAsManyAsPossible(){
try{
while (true) {
new Thread(new Runnable() {
public void run() {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
}
}
}).start();
}
}catch (Throwable e){
LOGGER.error(e.getMessage(),e);
}
}
docker 命令启动
docker run -v /tmp:/tmp –memory=256m -p 8080:8080 \
-e JAVA_OPTS=’-server -Xmx128m -Xss1m -XX:ParallelGCThreads=4 -XX:ConcGCThreads=4 -XX:+UnlockDiagnosticVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp’ \
-e PROFILE=’default’ \
demo
docker inspect containerId
[
{
“Id”: “93ec46e93290f8dc70901680c251dd9faef4a5a283cb6020ec8640fed4001026”,
“Created”: “2019-04-01T02:22:41.007466012Z”,
//……
“State”: {
“Status”: “exited”,
“Running”: false,
“Paused”: false,
“Restarting”: false,
“OOMKilled”: true,
“Dead”: false,
“Pid”: 0,
“ExitCode”: 137,
“Error”: “”,
“StartedAt”: “2019-04-01T02:22:41.284627718Z”,
“FinishedAt”: “2019-04-01T02:22:59.192763475Z”
},
“Image”: “sha256:bbaf9474dd259b8c6afe39cbbccce62bb695b52fda79d8ce3a727be89fcef5c6”,
//……
]
可以看到 State 里头的 OOMKilled 为 true
OutOfMemoryError 实例
代码实例
public void createThreadAsManyAsPossible(){
try{
while (true) {
new Thread(new Runnable() {
public void run() {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
}
}
}).start();
}
}catch (Throwable e){
LOGGER.error(e.getMessage(),e);
}
}
运行参数
-server
-Xmx128m
-Xss1m
-XX:ParallelGCThreads=4
-XX:ConcGCThreads=4
-XX:+UnlockDiagnosticVMOptions
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp
-Djava.io.tmpdir=/tmp
不使用 docker,直接在本机执行,可以看到如下报错
异常输出
java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
at java.base/java.lang.Thread.start0(Native Method) ~[na:na]
at java.base/java.lang.Thread.start(Thread.java:804) ~[na:na]
查看 thread 信息
查看 thread stack size
/ # jcmd 1 VM.native_memory scale=MB
1:
Native Memory Tracking:
Total: reserved=1321MB, committed=204MB
– Java Heap (reserved=128MB, committed=121MB)
(mmap: reserved=128MB, committed=121MB)
– Class (reserved=1065MB, committed=46MB)
(classes #8234)
(instance classes #7694, array classes #540)
(malloc=1MB #19759)
(mmap: reserved=1064MB, committed=44MB)
(Metadata:)
(reserved=40MB, committed=39MB)
(used=38MB)
(free=1MB)
(waste=0MB =0.00%)
(Class space:)
(reserved=1024MB, committed=6MB)
(used=5MB)
(free=0MB)
(waste=0MB =0.00%)
– Thread (reserved=36MB, committed=2MB)
(thread #36)
(stack: reserved=36MB, committed=2MB)
– Code (reserved=65MB, committed=11MB)
(malloc=1MB #4218)
(mmap: reserved=65MB, committed=10MB)
– GC (reserved=9MB, committed=7MB)
(malloc=5MB #6043)
(mmap: reserved=4MB, committed=2MB)
– Internal (reserved=4MB, committed=4MB)
(malloc=2MB #3454)
(mmap: reserved=2MB, committed=2MB)
– Symbol (reserved=10MB, committed=10MB)
(malloc=7MB #220126)
(arena=3MB #1)
– Native Memory Tracking (reserved=4MB, committed=4MB)
(tracking overhead=4MB)
使用 jcmd pid VM.native_memory scale=MB 可以查看 thread stack 的信息,具体在 Thread 部分,这里显示一共有 36 个线程,stack 的 reserved 大小为 36M
查看线程快照
/ # jcmd 1 Thread.print
1:
2019-04-01 10:43:13
Full thread dump OpenJDK 64-Bit Server VM (12+33 mixed mode):
Threads class SMR info:
_java_thread_list=0x0000562b1182fe30, length=28, elements={
0x0000562b0ffa5000, 0x0000562b0ffaa000, 0x0000562b0ffdc000, 0x0000562b0ffde800,
0x0000562b0ffe1000, 0x0000562b1003d800, 0x0000562b1016b000, 0x0000562b1017f800,
0x0000562b1141f800, 0x0000562b10a74000, 0x0000562b10b64000, 0x0000562b10fee800,
0x0000562b125d1000, 0x0000562b1040d800, 0x0000562b11983800, 0x0000562b11982000,
0x0000562b10cc7800, 0x0000562b13630800, 0x0000562b13632000, 0x0000562b136f0800,
0x0000562b136e0800, 0x0000562b136e1800, 0x0000562b13621800, 0x0000562b1360c000,
0x0000562b136cd000, 0x0000562b12115000, 0x0000562b11f9e000, 0x0000562b11ff8800
}
“Reference Handler” #2 daemon prio=10 os_prio=0 cpu=2.69ms elapsed=31.15s tid=0x0000562b0ffa5000 nid=0xb waiting on condition [0x00007f5cbb576000]
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@12/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@12/Reference.java:241)
at java.lang.ref.Reference$ReferenceHandler.run(java.base@12/Reference.java:213)
“Finalizer” #3 daemon prio=8 os_prio=0 cpu=0.25ms elapsed=31.15s tid=0x0000562b0ffaa000 nid=0xc in Object.wait() [0x00007f5cbb475000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@12/Native Method)
– waiting on <0x00000000f800a840> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@12/ReferenceQueue.java:155)
– locked <0x00000000f800a840> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@12/ReferenceQueue.java:176)
at java.lang.ref.Finalizer$FinalizerThread.run(java.base@12/Finalizer.java:170)
“Signal Dispatcher” #4 daemon prio=9 os_prio=0 cpu=0.79ms elapsed=31.14s tid=0x0000562b0ffdc000 nid=0xd runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
“C2 CompilerThread0” #5 daemon prio=9 os_prio=0 cpu=4680.36ms elapsed=31.14s tid=0x0000562b0ffde800 nid=0xe waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
No compile task
“C1 CompilerThread0” #6 daemon prio=9 os_prio=0 cpu=2329.95ms elapsed=31.14s tid=0x0000562b0ffe1000 nid=0xf waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
No compile task
“Sweeper thread” #7 daemon prio=9 os_prio=0 cpu=71.45ms elapsed=31.13s tid=0x0000562b1003d800 nid=0x10 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
“Service Thread” #8 daemon prio=9 os_prio=0 cpu=47.53ms elapsed=31.06s tid=0x0000562b1016b000 nid=0x11 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
“Common-Cleaner” #9 daemon prio=8 os_prio=0 cpu=3.92ms elapsed=31.05s tid=0x0000562b1017f800 nid=0x13 in Object.wait() [0x00007f5cbad6c000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@12/Native Method)
– waiting on <0x00000000f80c1880> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@12/ReferenceQueue.java:155)
– locked <0x00000000f80c1880> (a java.lang.ref.ReferenceQueue$Lock)
at jdk.internal.ref.CleanerImpl.run(java.base@12/CleanerImpl.java:148)
at java.lang.Thread.run(java.base@12/Thread.java:835)
at jdk.internal.misc.InnocuousThread.run(java.base@12/InnocuousThread.java:134)
“Catalina-utility-1” #13 prio=1 os_prio=0 cpu=9.33ms elapsed=19.61s tid=0x0000562b1141f800 nid=0x19 waiting on condition [0x00007f5cb93ac000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000ffac03b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@12/ScheduledThreadPoolExecutor.java:1177)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@12/ScheduledThreadPoolExecutor.java:899)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“Catalina-utility-2” #14 prio=1 os_prio=0 cpu=2.97ms elapsed=19.61s tid=0x0000562b10a74000 nid=0x1a waiting on condition [0x00007f5cb827d000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000ffac03b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@12/LockSupport.java:235)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@12/AbstractQueuedSynchronizer.java:2123)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@12/ScheduledThreadPoolExecutor.java:1182)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@12/ScheduledThreadPoolExecutor.java:899)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“container-0” #15 prio=5 os_prio=0 cpu=0.16ms elapsed=19.60s tid=0x0000562b10b64000 nid=0x1b waiting on condition [0x00007f5cb817c000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@12/Native Method)
at org.apache.catalina.core.StandardServer.await(StandardServer.java:568)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer$1.run(TomcatWebServer.java:181)
“Thread-1” #16 daemon prio=9 os_prio=0 cpu=0.26ms elapsed=19.38s tid=0x0000562b10fee800 nid=0x1c waiting on condition [0x00007f5cb7f25000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fe2f54f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.LatencyUtils.PauseDetector$PauseDetectorThread.run(PauseDetector.java:85)
“SimplePauseDetectorThread_0” #17 daemon prio=9 os_prio=0 cpu=20.21ms elapsed=19.37s tid=0x0000562b125d1000 nid=0x1d waiting on condition [0x00007f5cb7e24000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@12/Native Method)
at java.lang.Thread.sleep(java.base@12/Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(java.base@12/TimeUnit.java:446)
at org.LatencyUtils.TimeServices.sleepNanos(TimeServices.java:62)
at org.LatencyUtils.SimplePauseDetector$SimplePauseDetectorThread.run(SimplePauseDetector.java:116)
“NioBlockingSelector.BlockPoller-1” #18 daemon prio=5 os_prio=0 cpu=2.27ms elapsed=17.43s tid=0x0000562b1040d800 nid=0x23 runnable [0x00007f5cba443000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPoll.wait(java.base@12/Native Method)
at sun.nio.ch.EPollSelectorImpl.doSelect(java.base@12/EPollSelectorImpl.java:120)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@12/SelectorImpl.java:124)
– locked <0x00000000fb4b21c0> (a sun.nio.ch.Util$2)
– locked <0x00000000fb4b1dc8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(java.base@12/SelectorImpl.java:136)
at org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run(NioBlockingSelector.java:304)
“http-nio-8080-exec-1” #19 daemon prio=5 os_prio=0 cpu=0.13ms elapsed=17.42s tid=0x0000562b11983800 nid=0x24 waiting on condition [0x00007f5cb7d23000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-2” #20 daemon prio=5 os_prio=0 cpu=0.09ms elapsed=17.42s tid=0x0000562b11982000 nid=0x25 waiting on condition [0x00007f5cb807b000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-3” #21 daemon prio=5 os_prio=0 cpu=0.35ms elapsed=17.42s tid=0x0000562b10cc7800 nid=0x26 waiting on condition [0x00007f5cb77e5000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-4” #22 daemon prio=5 os_prio=0 cpu=0.10ms elapsed=17.42s tid=0x0000562b13630800 nid=0x27 waiting on condition [0x00007f5cb75ff000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-5” #23 daemon prio=5 os_prio=0 cpu=0.06ms elapsed=17.41s tid=0x0000562b13632000 nid=0x28 waiting on condition [0x00007f5cb74fe000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-6” #24 daemon prio=5 os_prio=0 cpu=0.14ms elapsed=17.41s tid=0x0000562b136f0800 nid=0x29 waiting on condition [0x00007f5cb73fd000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-7” #25 daemon prio=5 os_prio=0 cpu=0.12ms elapsed=17.41s tid=0x0000562b136e0800 nid=0x2a waiting on condition [0x00007f5cb72fc000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-8” #26 daemon prio=5 os_prio=0 cpu=0.09ms elapsed=17.41s tid=0x0000562b136e1800 nid=0x2b waiting on condition [0x00007f5cb71fb000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-9” #27 daemon prio=5 os_prio=0 cpu=0.14ms elapsed=17.41s tid=0x0000562b13621800 nid=0x2c waiting on condition [0x00007f5cb70fa000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-exec-10” #28 daemon prio=5 os_prio=0 cpu=0.14ms elapsed=17.41s tid=0x0000562b1360c000 nid=0x2d waiting on condition [0x00007f5cb6ff9000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@12/Native Method)
– parking to wait for <0x00000000fb50ba60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(java.base@12/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@12/AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(java.base@12/LinkedBlockingQueue.java:433)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@12/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@12/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@12/ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-ClientPoller-0” #29 daemon prio=5 os_prio=0 cpu=2.85ms elapsed=17.40s tid=0x0000562b136cd000 nid=0x2e runnable [0x00007f5cb6ef8000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPoll.wait(java.base@12/Native Method)
at sun.nio.ch.EPollSelectorImpl.doSelect(java.base@12/EPollSelectorImpl.java:120)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@12/SelectorImpl.java:124)
– locked <0x00000000fb53c5f8> (a sun.nio.ch.Util$2)
– locked <0x00000000fb53c460> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(java.base@12/SelectorImpl.java:136)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:743)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“http-nio-8080-Acceptor-0” #30 daemon prio=5 os_prio=0 cpu=0.45ms elapsed=17.40s tid=0x0000562b12115000 nid=0x2f runnable [0x00007f5cb6df7000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.ServerSocketChannelImpl.accept0(java.base@12/Native Method)
at sun.nio.ch.ServerSocketChannelImpl.accept(java.base@12/ServerSocketChannelImpl.java:525)
at sun.nio.ch.ServerSocketChannelImpl.accept(java.base@12/ServerSocketChannelImpl.java:277)
at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:448)
at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:70)
at org.apache.tomcat.util.net.Acceptor.run(Acceptor.java:95)
at java.lang.Thread.run(java.base@12/Thread.java:835)
“DestroyJavaVM” #32 prio=5 os_prio=0 cpu=4915.44ms elapsed=17.32s tid=0x0000562b11f9e000 nid=0x6 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
“Attach Listener” #33 daemon prio=9 os_prio=0 cpu=0.60ms elapsed=15.49s tid=0x0000562b11ff8800 nid=0x3c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
“VM Thread” os_prio=0 cpu=170.49ms elapsed=31.16s tid=0x0000562b0ff90000 nid=0xa runnable
“Shenandoah GC Threads#0” os_prio=0 cpu=57.15ms elapsed=31.46s tid=0x0000562b0fe25800 nid=0x7 runnable
“Shenandoah GC Threads#1” os_prio=0 cpu=40.46ms elapsed=29.33s tid=0x0000562b111b0000 nid=0x15 runnable
“Shenandoah GC Threads#2” os_prio=0 cpu=56.93ms elapsed=29.32s tid=0x0000562b111ae000 nid=0x16 runnable
“Shenandoah GC Threads#3” os_prio=0 cpu=47.89ms elapsed=29.30s tid=0x0000562b11562800 nid=0x17 runnable
“VM Periodic Task Thread” os_prio=0 cpu=59.59ms elapsed=31.06s tid=0x0000562b1016e000 nid=0x12 waiting on condition
JNI global refs: 14, weak refs: 0
使用 jcmd pid Thread.print 可以打印线程快照
查看 spring boot 运行线程信息
/ # curl -i localhost:8080/actuator/metrics/jvm.threads.daemon
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 01 Apr 2019 02:49:19 GMT
{“name”:”jvm.threads.daemon”,”description”:”The current number of live daemon threads”,”baseUnit”:”threads”,”measurements”:[{“statistic”:”VALUE”,”value”:20.0}],”availableTags”:[]}
/ # curl -i localhost:8080/actuator/metrics/jvm.threads.peak
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 01 Apr 2019 02:47:32 GMT
{“name”:”jvm.threads.peak”,”description”:”The peak live thread count since the Java virtual machine started or peak was reset”,”baseUnit”:”threads”,”measurements”:[{“statistic”:”VALUE”,”value”:24.0}],”availableTags”:[]}
/ # curl -i localhost:8080/actuator/metrics/jvm.threads.live
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 01 Apr 2019 02:47:52 GMT
{“name”:”jvm.threads.live”,”description”:”The current number of live threads including both daemon and non-daemon threads”,”baseUnit”:”threads”,”measurements”:[{“statistic”:”VALUE”,”value”:24.0}],”availableTags”:[]}
/ # curl -i localhost:8080/actuator/metrics/tomcat.threads.current
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 01 Apr 2019 02:48:31 GMT
{“name”:”tomcat.threads.current”,”description”:null,”baseUnit”:”threads”,”measurements”:[{“statistic”:”VALUE”,”value”:10.0}],”availableTags”:[{“tag”:”name”,”values”:[“http-nio-8080”]}]}
/ # curl -i localhost:8080/actuator/metrics/tomcat.threads.busy
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 01 Apr 2019 02:48:58 GMT
{“name”:”tomcat.threads.busy”,”description”:null,”baseUnit”:”threads”,”measurements”:[{“statistic”:”VALUE”,”value”:1.0}],”availableTags”:[{“tag”:”name”,”values”:[“http-nio-8080”]}]}
/ # curl -i localhost:8080/actuator/metrics/tomcat.threads.config.max
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 01 Apr 2019 02:50:15 GMT
{“name”:”tomcat.threads.config.max”,”description”:null,”baseUnit”:”threads”,”measurements”:[{“statistic”:”VALUE”,”value”:200.0}],”availableTags”:[{“tag”:”name”,”values”:[“http-nio-8080”]}]}
springboot 的 actuator 默认可以查看 jvm.threads 开头 (jvm.threads.daemon、jvm.threads.peak、jvm.threads.live) 以及 tomcat.threads 开头 (tomcat.threads.current、tomcat.threads.busy、tomcat.threads.config.max) 的 metrics;另外使用 /actuator/threaddump 也可以打印线程快照;不过 actuator 的 metrics 没有统计也没有 dump 出来 gc 等其他线程,比如 C2 CompilerThread0、C1 CompilerThread0、Sweeper thread、Service Thread、VM Thread、Shenandoah GC Threads#0、Shenandoah GC Threads#1、Shenandoah GC Threads#2、Shenandoah GC Threads#3、VM Periodic Task Thread 等
小结
每个 jvm 线程都有一个私有的 Virtual Machine Stack,它在线程同时被创建;该 stack 主要用于存储 frames,即所谓的 stack frames;每个方法在执行的时候都会创建一个 stack frame,用于存储方法的局部变量、返回值、Operand stack 等
Stack Memory 是执行线程时所使用的内存,他们包含了方法用到的一些短生命周期的 values 及 heap 中 objects 的引用;Stack Memory 是按照 LIFO (Last-In-First-Out)的顺序被引用的,每当一个方法被调用,都会在 stack memory 中创建一块区域用于保存原始类型的值及 heap 中 objects 的引用;当方法执行结束时,这块区域就被释放可以被下一个方法使用;相对于 heap memory 来说,stack memory 是非常小的一块。通过 -Xss 或者 -XX:ThreadStackSize 可以指定 stack memory 的大小;当一个线程所需的 stack size 超过了设定的大小是,jvm 会抛出 StackOverflowError;而当系统没有足够内存可以供 jvm 创建一个新线程时,jvm 会抛出 OutOfMemoryError
查询线程信息
使用 jcmd pid VM.native_memory scale=MB 可以查看 thread stack 的信息,具体在 Thread 部分
使用 jcmd pid Thread.print 可以打印线程快照
springboot 的 actuator 默认可以查看 jvm.threads 开头 (jvm.threads.daemon、jvm.threads.peak、jvm.threads.live) 以及 tomcat.threads 开头 (tomcat.threads.current、tomcat.threads.busy、tomcat.threads.config.max) 的 metrics
使用 /actuator/threaddump 也可以打印线程快照(不过 actuator 的 metrics 没有统计也没有 dump 出来 gc 等其他线程)
doc
Java 线程与 Xss
2.5.2. Java Virtual Machine Stacks
JVMInternals
JVM memory model
Java Heap Space vs Stack – Memory Allocation in Java
How does Java (JVM) allocate stack for each thread
JVM Stacks and Stack Frames
A Visual Look at JVM Stacks and Frames
Stack Memory and Heap Space in Java
Java: What is the limit to the number of threads you can create?
Troubleshoot OutOfMemoryError: Unable to Create New Native Thread
JDK 8: Thread Stack Size Tuning
JVM Tuning: Heapsize, Stacksize and Garbage Collection Fundamental