聊聊jvm的Stack Memory

本文主要研究一下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

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励