【问题标题】:Does -XX:+UseSerialGC use main thread for GC-XX:+UseSerialGC 是否使用主线程进行 GC
【发布时间】:2023-04-07 13:47:01
【问题描述】:

我一直在阅读(例如herehere),-XX:+UseSerialGC 垃圾收集器仅使用单线程进行垃圾收集。但不清楚这个“单线程”是main线程还是不同的单GC线程。

所以,我使用和不使用-XX:+UseSerialGC 进行了线程转储,在我看来,当使用此选项时,GC 由main 线程执行,因为我没有看到任何 GC 线程(如"GC task thread#0 (ParallelGC)")当我使用-XX:+UseSerialGC时。

请有JVM和GC方面经验和知识的人确认或更正我的理解。

没有-XX:+UseSerialGC

2018-03-15 17:52:36
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x000000001d88d800 nid=0x1e64 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000000001d809000 nid=0x2598 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000000001d806800 nid=0x30d8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001d801800 nid=0x1338 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001d800800 nid=0x306c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001c18b800 nid=0x323c runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001c16d000 nid=0x2dd0 in Object.wait() [0x000000001d7fe000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f2011d8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x000000076f2011d8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001c12b800 nid=0x28a8 in Object.wait() [0x000000001d61f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f208178> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x000000076f208178> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x000000000223d000 nid=0x3174 runnable [0x00000000026ef000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:326)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    - locked <0x000000076f2240c0> (a java.io.BufferedOutputStream)
    at java.io.PrintStream.write(PrintStream.java:482)
    - locked <0x000000076f201258> (a java.io.PrintStream)
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
    at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
    - locked <0x000000076f201218> (a java.io.OutputStreamWriter)
    at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
    at java.io.PrintStream.write(PrintStream.java:527)
    - locked <0x000000076f201258> (a java.io.PrintStream)
    at java.io.PrintStream.print(PrintStream.java:669)
    at com.learn.stackoverflow.general.memory.GCThreadCount.main(GCThreadCount.java:12)

"VM Thread" os_prio=2 tid=0x000000001c124000 nid=0x25e0 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002256000 nid=0x3198 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002257800 nid=0x1ed4 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002259000 nid=0x199c runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000225a800 nid=0x2870 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x000000001d8ad800 nid=0x1fa0 waiting on condition 

JNI global references: 8


With 2018-03-15 17:52:36
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x000000001d88d800 nid=0x1e64 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000000001d809000 nid=0x2598 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000000001d806800 nid=0x30d8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001d801800 nid=0x1338 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001d800800 nid=0x306c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001c18b800 nid=0x323c runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001c16d000 nid=0x2dd0 in Object.wait() [0x000000001d7fe000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f2011d8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x000000076f2011d8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001c12b800 nid=0x28a8 in Object.wait() [0x000000001d61f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f208178> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x000000076f208178> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x000000000223d000 nid=0x3174 runnable [0x00000000026ef000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:326)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    - locked <0x000000076f2240c0> (a java.io.BufferedOutputStream)
    at java.io.PrintStream.write(PrintStream.java:482)
    - locked <0x000000076f201258> (a java.io.PrintStream)
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
    at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
    - locked <0x000000076f201218> (a java.io.OutputStreamWriter)
    at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
    at java.io.PrintStream.write(PrintStream.java:527)
    - locked <0x000000076f201258> (a java.io.PrintStream)
    at java.io.PrintStream.print(PrintStream.java:669)
    at com.learn.stackoverflow.general.memory.GCThreadCount.main(GCThreadCount.java:12)

"VM Thread" os_prio=2 tid=0x000000001c124000 nid=0x25e0 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002256000 nid=0x3198 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002257800 nid=0x1ed4 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002259000 nid=0x199c runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000225a800 nid=0x2870 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x000000001d8ad800 nid=0x1fa0 waiting on condition 

JNI global references: 8

-XX:+UseSerialGC

2018-03-15 17:54:47
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x000000001351a000 nid=0x2388 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x0000000013492000 nid=0x2630 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x0000000013490000 nid=0x3084 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001348b000 nid=0x32cc waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000013489800 nid=0x3334 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000013488000 nid=0xcc0 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000013469800 nid=0x3144 in Object.wait() [0x000000001380f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000006c5a60d18> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000006c5a60d18> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000013422000 nid=0xf20 in Object.wait() [0x000000000259e000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000006c5a60ed0> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x00000006c5a60ed0> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x00000000022cd000 nid=0x332c runnable [0x000000000274f000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:326)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    - locked <0x00000006c5a6e000> (a java.io.BufferedOutputStream)
    at java.io.PrintStream.write(PrintStream.java:482)
    - locked <0x00000006c5a60f20> (a java.io.PrintStream)
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
    at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
    - locked <0x00000006c5a60ee0> (a java.io.OutputStreamWriter)
    at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
    at java.io.PrintStream.write(PrintStream.java:527)
    - locked <0x00000006c5a60f20> (a java.io.PrintStream)
    at java.io.PrintStream.print(PrintStream.java:669)
    at com.learn.stackoverflow.general.memory.GCThreadCount.main(GCThreadCount.java:12)

"VM Thread" os_prio=2 tid=0x0000000013419000 nid=0x13e8 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x0000000014311000 nid=0x3364 waiting on condition 

JNI global references: 8

【问题讨论】:

  • 串行 GC 应该在本地 VM 线程上运行 - 而不是在任何 Java 线程上。
  • @AlexandreDupriez 感谢您的回复。能否请您详细说明。并行 GC 怎么样,对他们来说也是原生线程?
  • Java Performance Companion,第 2 页,第 1 章中有一个线索:[...] 对于 HotSpot 垃圾收集器,几乎所有多线程 GC 操作都被处理通过内部 Java VM (JVM) 线程。一个主要的例外是 G1 垃圾收集器,其中一些后台 GC 工作可以由应用程序线程承担。

标签: java multithreading memory memory-management garbage-collection


【解决方案1】:

如果启用串行GC,分配内存失败的线程用于执行垃圾回收。

如果您在此类 GC 期间进行混合线程转储,您可以从 Java 代码中的分配尝试中观察到 JVM GC 相关代码正在递归执行。

这是特定于单线程 GC 算法的。多线程 GC 的所有变体都使用 GC 工作者的专用线程池。

【讨论】:

  • 你有关于串行 GC 的参考吗?分配内存的线程是应用线程吗?
  • @AlexandreDupriez 为什么需要参考?如果您需要确认,您可以自己进行线程转储包括本机堆栈,这是 Alexey 的建议。
  • @the8472 因为否则在 stackoverflow 中询问(或回答)任何内容都没有意义。以某种方式,一切最终都可以通过发布者进行经验验证,避免发布问题。那会是一个更美好的世界吗?值得怀疑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多