日志分析
文章目录
日志举例一
Java HotSpot(TM) 64-Bit Server VM (25.202-b08) for linux-amd64 JRE (1.8.0_202-b08), built on Dec 15 2018 12:40:22 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 98838152k(4043244k free), swap 16777212k(9148048k free)
CommandLine flags: -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSScavengeBeforeRemark -XX:CompressedClassSpaceSize=260046848 -XX:+DisableExplicitGC -XX:ErrorFile=/var/app/gc/hs_err_pid%p.log -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/app/gc -XX:InitialHeapSize=2818572288 -XX:MaxHeapSize=2818572288 -XX:MaxMetaspaceSize=268435456 -XX:MaxNewSize=1006632960 -XX:MaxTenuringThreshold=6 -XX:MetaspaceSize=268435456 -XX:NewSize=1006632960 -XX:OldPLABSize=16 -XX:+ParallelRefProcEnabled -XX:+PrintGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
2023-08-09T09:56:16.529+0000: 0.436: Total time for which application threads were stopped: 0.0002870 seconds, Stopping threads took: 0.0000777 seconds
2023-08-09T09:56:16.582+0000: 0.489: Total time for which application threads were stopped: 0.0001678 seconds, Stopping threads took: 0.0000354 seconds
2023-08-09T09:56:17.059+0000: 0.966: Total time for which application threads were stopped: 0.0003279 seconds, Stopping threads took: 0.0000319 seconds
2023-08-09T09:56:17.194+0000: 1.101: Total time for which application threads were stopped: 0.0003068 seconds, Stopping threads took: 0.0000202 seconds
2023-08-09T09:56:17.256+0000: 1.163: Total time for which application threads were stopped: 0.0003321 seconds, Stopping threads took: 0.0001093 seconds
2023-08-09T09:56:17.485+0000: 1.392: Total time for which application threads were stopped: 0.0005075 seconds, Stopping threads took: 0.0001826 seconds
2023-08-09T09:56:17.510+0000: 1.416: Total time for which application threads were stopped: 0.0023176 seconds, Stopping threads took: 0.0020402 seconds
2023-08-09T09:56:17.831+0000: 1.738: Total time for which application threads were stopped: 0.0004216 seconds, Stopping threads took: 0.0001025 seconds
2023-08-09T09:56:17.910+0000: 1.817: Total time for which application threads were stopped: 0.0003990 seconds, Stopping threads took: 0.0000672 seconds
2023-08-09T09:56:18.100+0000: 2.007: Total time for which application threads were stopped: 0.0001958 seconds, Stopping threads took: 0.0000334 seconds
2023-08-09T09:56:18.315+0000: 2.222: Total time for which application threads were stopped: 0.0004638 seconds, Stopping threads took: 0.0000256 seconds
2023-08-09T09:56:18.316+0000: 2.223: Total time for which application threads were stopped: 0.0002114 seconds, Stopping threads took: 0.0000163 seconds
2023-08-09T09:56:18.553+0000: 2.460: Total time for which application threads were stopped: 0.0004370 seconds, Stopping threads took: 0.0000176 seconds
2023-08-09T09:56:18.594+0000: 2.501: Total time for which application threads were stopped: 0.0037669 seconds, Stopping threads took: 0.0033805 seconds
2023-08-09T09:56:18.658+0000: 2.564: Total time for which application threads were stopped: 0.0004332 seconds, Stopping threads took: 0.0000330 seconds
{Heap before GC invocations=0 (full 0):
par new generation total 884736K, used 786432K [0x0000000748800000, 0x0000000784800000, 0x0000000784800000)
eden space 786432K, 100% used [0x0000000748800000, 0x0000000778800000, 0x0000000778800000)
from space 98304K, 0% used [0x0000000778800000, 0x0000000778800000, 0x000000077e800000)
to space 98304K, 0% used [0x000000077e800000, 0x000000077e800000, 0x0000000784800000)
concurrent mark-sweep generation total 1769472K, used 0K [0x0000000784800000, 0x00000007f0800000, 0x00000007f0800000)
Metaspace used 25279K, capacity 26130K, committed 26368K, reserved 1073152K
class space used 3298K, capacity 3497K, committed 3584K, reserved 1048576K
2023-08-09T09:56:18.786+0000: 2.693: [GC (Allocation Failure) 2023-08-09T09:56:18.786+0000: 2.693: [ParNew: 786432K->9099K(884736K), 0.0692137 secs] 786432K->9099K(2654208K), 0.0693093 secs] [Times: user=0.08 sys=0.00, real=0.07 secs]
Heap after GC invocations=1 (full 0):
par new generation total 884736K, used 9099K [0x0000000748800000, 0x0000000784800000, 0x0000000784800000)
eden space 786432K, 0% used [0x0000000748800000, 0x0000000748800000, 0x0000000778800000)
from space 98304K, 9% used [0x000000077e800000, 0x000000077f0e2c90, 0x0000000784800000)
to space 98304K, 0% used [0x0000000778800000, 0x0000000778800000, 0x000000077e800000)
concurrent mark-sweep generation total 1769472K, used 0K [0x0000000784800000, 0x00000007f0800000, 0x00000007f0800000)
Metaspace used 25279K, capacity 26130K, committed 26368K, reserved 1073152K
class space used 3298K, capacity 3497K, committed 3584K, reserved 1048576K
}
2023-08-09T09:56:18.856+0000: 2.762: Total time for which application threads were stopped: 0.0695623 seconds, Stopping threads took: 0.0000300 seconds
日志举例二
[GC (Allocation Failure) [DefNew: 4669K->330K(4928K), 0.0011597 secs] 9235K->4897K(15872K), 0.0011820 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 4746K->316K(4928K), 0.0011910 secs] 9313K->4966K(15872K), 0.0012126 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 4732K->237K(4928K), 0.0012076 secs] 9382K->4968K(15872K), 0.0012277 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[GC (GCLocker Initiated GC) [DefNew: 4653K->262K(4928K), 0.0012791 secs] 9385K->4993K(15872K), 0.0012996 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 4674K->332K(4928K), 0.0010540 secs] 9406K->5093K(15872K), 0.0010742 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 4748K->185K(4928K), 0.0013724 secs] 9509K->5054K(15872K), 0.0013924 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
一,日志解读
Java HotSpot(TM) 64-Bit Server VM (25.202-b08) for linux-amd64 JRE (1.8.0_202-b08), built on Dec 15 2018 12:40:22 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 98838152k(4043244k free), swap 16777212k(9148048k free)
CommandLine flags:
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingOccupancyFraction=70
-XX:+CMSScavengeBeforeRemark
-XX:CompressedClassSpaceSize=260046848
-XX:+DisableExplicitGC
-XX:ErrorFile=/var/app/gc/hs_err_pid%p.log
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/app/gc
-XX:InitialHeapSize=2818572288
-XX:MaxHeapSize=2818572288
-XX:MaxMetaspaceSize=268435456
-XX:MaxNewSize=1006632960
-XX:MaxTenuringThreshold=6
-XX:MetaspaceSize=268435456
-XX:NewSize=1006632960
-XX:OldPLABSize=16
-XX:+ParallelRefProcEnabled
-XX:+PrintGC
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
这里分为三部分信息:版本和环境、内存、命令行参数:
-
第一行:版本和环境信息。构成:虚拟机的版本信息 for 操作系统信息,built on JDK的构建信息
-
第二行:内存信息。构成:内存页大小 page,physical 物理内存xxx(xxx 空闲free)swap 交换分区xxx(xxx 空闲free)
-
第三行:命令行参数信息。这里面的参数和启动参数之间是存在一些关系和差异的。有一些是和启动参数配置一样的,只是把(G/M/K)数值转化为了字节而已。需要重点关注的是以下两类:
-
意义一样名字有变化
-XX:InitialHeapSize 对应启动参数里的 -Xms
-XX:MaxHeapSize 对应启动参数里的 -Xmx
-
启动参数里没有设置的但是这里出现的
例如:-XX:+PrintGC等等
-
2023-08-09T09:56:16.529+0000: 0.436: Total time for which application threads were stopped: 0.0002870 seconds, Stopping threads took: 0.0000777 seconds
-
2023-08-09T09:56:16.529+0000: 0.436:GC发生的时间
-
Total time for which application threads were stopped: 0.0002870 seconds, Stopping threads took: 0.0000777 seconds:文件中会出现大量类似行日志,行数表示VM operation overhead数。当GC发生时,每个线程只有进入了SafePoint才算是真正挂起,也就是真正的停顿,这个日志的含义是整个GC过程中STW的时间,配置了 -XX:+PrintGCApplicationStoppedTime 这个参数才会打印这个信息。
- 第一个 0.0002870 seconds 是JVM启动后的秒数,
- 第二个 0.0000777 seconds 是 JVM发起STW的开始到结束的时间。
特别地,如果是GC引发的STW,这条内容会紧挨着出现在GC log的下面。
{Heap before GC invocations=0 (full 0):
par new generation total 884736K, used 786432K [0x0000000748800000, 0x0000000784800000, 0x0000000784800000)
eden space 786432K, 100% used [0x0000000748800000, 0x0000000778800000, 0x0000000778800000)
from space 98304K, 0% used [0x0000000778800000, 0x0000000778800000, 0x000000077e800000)
to space 98304K, 0% used [0x000000077e800000, 0x000000077e800000, 0x0000000784800000)
concurrent mark-sweep generation total 1769472K, used 0K [0x0000000784800000, 0x00000007f0800000, 0x00000007f0800000)
Metaspace used 25279K, capacity 26130K, committed 26368K, reserved 1073152K
class space used 3298K, capacity 3497K, committed 3584K, reserved 1048576K
这是gc开始之前堆和元数据信息
该日志一般出现在GC操作之前,在GC操作之后会再次打印年轻代占用内存情况,可做对比。
-
Heap before GC invocations=0 (full 0):GC前的堆内存占用情况。invocations=0说明本次gc开始之前,已经经历过0次垃圾回收。其中full gc是0次。
-
par new generation total 884736K, used 786432K:使用parnew,表示年轻代堆内存总共884736K,已经使用786432K 。
-
eden space 786432K, 100% used[0x0000000748800000, 0x0000000778800000, 0x0000000778800000):年轻代Eden区域的内存大小,使用情况,对应区的内存区域起始内存标记位,已使用的内存地址标记位,空间结束位置的标记位
-
from space 98304K, 0% used:年轻代Survivor中FromSpace区域的内存大小,以及使用情况
-
to space 98304K, 0% used:年轻代Survivor中ToSpace区域的内存大小,以及使用情况
-
concurrent mark-sweep generation total 1769472K, used 0K:老年代所占内存情况,以及使用情况
-
Metaspace used 25279K, capacity 26130K, committed 26368K, reserved 1073152K:程序元空间内存占用情况(非JVM)
- used:加载的类的空间量,已使用大小
- capacity:当前分配块的源数据空间,总容量大小
- committed:空间块的大小,虚拟内存占用大小
- reserved:元数据的空间保留的量(并不一定是提交),保留空间大小
-
class space used 3298K, capacity 3497K, committed 3584K, reserved 1048576K:Metaspace 分为两个区域:non-class part 和 class part。class part被称为class spec。
=========================================== 日志举例一 ===========================================
2023-08-09T09:56:18.786+0000: 2.693: [GC (Allocation Failure) 2023-08-09T09:56:18.786+0000: 2.693: [ParNew: 786432K->9099K(884736K), 0.0692137 secs] 786432K->9099K(2654208K), 0.0693093 secs] [Times: user=0.08 sys=0.00, real=0.07 secs]
=========================================== 日志举例二 ===========================================
[GC (Allocation Failure) [DefNew: 4732K->237K(4928K), 0.0012076 secs] 9382K->4968K(15872K), 0.0012277 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[GC (GCLocker Initiated GC) [DefNew: 4653K->262K(4928K), 0.0012791 secs] 9385K->4993K(15872K), 0.0012996 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
-
GC:GC的类型,用来区分Minor GC还是Full GC的标志。这里指一次小型GC(Minor GC)
-
ParNew:垃圾回收器的名称,Par表示Parallel,New表示年轻代,Parnew指并行收集年轻代垃圾。
-
786432K->9099K(884736K):回收情况,表示年轻代回收前->回收后(年轻代内存大小)
-
0.0692137 secs:耗费时间
-
786432K->9099K(2654208K):表示堆内存回收前大小->堆内存回收后大小(堆总内存大小)
-
[Times: user=0.08 sys=0.00, real=0.07 secs] :GC事件的持续时间,通过三个部分衡量(由于并不是所有的操作过程都能全部并行,所以在并行GC中,real约等于user+system/GC线程数):
- user表示GC线程所消耗的总CPU时间
- sys表示操作系统和系统等待事件所消耗的时间
- real则表示应用程序实际暂停时间。
DefNew,ParNew,Turnred:表示GC发生的区域,这里显示的区域名称与使用的GC收集器是密切相关的
-
Allocation Failure:GC产生的原因。表示向young generation(eden)给新对象申请空间,但是young generation(eden)剩余的合适空间不够所需的大小导致的minor gc
另外几种常见的GC原因简介:
-
GCLocker Initiated GC:使用JNI临界区的方式操作数组或者字符串时,为了防止GC过程中jarray或者jstring发生位移,而导致数组指针失效,需要保持它们在JVM Heap中的地址在JNI Critical过程中保持不变。于是JVM实现了GC_locker,用于JNI Critical内阻止其他GC的发生。
当GCLocker被激活且需要发生GC的时候(这里是否需要GC是各种GC发生时,调用GCLocker::check_active_before_gc()函数check并设置needs_gc = true的),就会阻塞其他线程进入JNI临界区;并且在最后一个位于JNI临界区的线程退出临界区时,发起一次CGCause为gc_locker的GC。
-
Ergonomics:负责自动的调解gc暂停时间和吞吐量之间的平衡。内存在进行分配的时候,会通过一些算法,预估是否会出现无法分配的问题。如果符合无法分配预估值,会提前进行一次gc。
-
Metedata GC Threshold:主要发生的条件是元空间,也就是Metadata的参数设置问题。
JDK8中,XX:MaxMetaspaceSize确实是没有上限的,最大容量与机器的内存有关;但是XX:MetaspaceSize是有一个默认值的:21M。
GC触发的原因是因为Metaspace大小达到了GC阈值。
-
G1 Evacuation Pause:空间使用达到阈值,如果是young gc则意味着年轻代已满,如果是mixed gc则大多数情况下是老年代空间占整个堆空间比例达到阈值(默认45%)。
-
G1 Humongous Allocation:表示巨型对象空间分配申请。每一个巨型对象的的内存分配都会触发一次gc尝试,如果当前已经处在并发标记周期阶段了,则不会主动发起gc,否则会主动发起gc。
-
有时候我们会看到某些GC日志还包括GC细节过程中的耗时情况
如下为新生代内存空间进行回收日志:
[Parallel Time: 12.9 ms, GC Workers: 8] // 开启了8个GC线程
[GC Worker Start (ms): Min: 3926.9, Avg: 3934.2, Max: 3939.7, Diff: 12.8] // 工作线程启动时间
[Ext Root Scanning (ms): Min: 0.0, Avg: 0.3, Max: 2.5, Diff: 2.5, Sum: 2.6] //扫描root的耗时
[Update RS (ms): Min: 0.0, Avg: 0.3, Max: 2.1, Diff: 2.1, Sum: 2.1] //更新RS的耗时
[Processed Buffers: Min: 0, Avg: 1.9, Max: 15, Diff: 15, Sum: 15]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.0, Sum: 0.1] //扫描RS的耗时
[Code Root Scanning (ms): Min: 0.0, Avg: 0.1, Max: 0.6, Diff: 0.6, Sum: 0.6] //
[Object Copy (ms): Min: 0.0, Avg: 4.5, Max: 7.1, Diff: 7.1, Sum: 35.9] //对象拷贝耗时
[Termination (ms): Min: 0.0, Avg: 0.4, Max: 0.5, Diff: 0.5, Sum: 2.9]
[Termination Attempts: Min: 1, Avg: 74.2, Max: 133, Diff: 132, Sum: 594]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
[GC Worker Total (ms): Min: 0.0, Avg: 5.5, Max: 12.8, Diff: 12.8, Sum: 44.3]
[GC Worker End (ms): Min: 3939.7, Avg: 3939.7, Max: 3939.8, Diff: 0.0]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 1.1 ms] //其它任务的耗时
[Choose CSet: 0.0 ms] //CSet选择Region的时间
[Ref Proc: 0.7 ms] //处理对象引用的时间
[Ref Enq: 0.0 ms] //引用入ReferenceQueues队列的时间
[Redirty Cards: 0.2 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms] //释放CSet时间
[Eden: 52.0M(52.0M)->0.0B(52.0M) Survivors: 8192.0K->8192.0K Heap: 74.2M(100.0M)->25.6M(100.0M)]
Eden 回收前用量(总容量)->回收后用量(总容量),Survivors区回收前用量-回收后用量, 堆内存回收前用量(总容量)->回收后用量(总容量)
二,相关概念
2.1 SafePoint
概念
A point during program execution at which all GC roots are known and all heap object contents are consistent. From a global point of view, all threads must block at a safepoint before the GC can run. (Except thread running JNI code)
在SafePoint时,所有的 GC Roots 和堆对象内容将保持一致。从全局来看,所有的线程需要在该时刻阻塞,以便于执行 GC。
何种情况下进入SafePoint
在JVM中,存在一个单例的原始线程VM Thread,它会产生创建所有其他JVM线程,同时也会被其他线程用于执行一些成本较高的VM Operions。这些VM Operations会保存在VMOperationQueue中,通过自轮询方法loop()进行处理。
而在VM Thread退出及轮询处理VM Operations的过程中,需要STW来保证结果的准确性,就调用 SafepointSynchronize::begin() 进入SafePoint。而处理完VM Operations后,通过调用 SafepointSynchronize::end() 退出。
-
VM Thread退出时:JVM即将关闭,此时会进入
SafePoint,进行退出前的检查,并等待native thread执行完毕,最终关闭整个JVM。(此时只有begin,没有end,因为JVM已经要关闭了) -
处理VM Operation时:在处理一些JVM行为时,会进入
SafePoint,这些JVM行为定义在vm_operations.hpp 中。总体可以归结在以下几个行为类别中:
(1)Garbage collection pauses(垃圾回收)
(2)JIT相关,比如Code deoptimization, Flushing code cache
(3)Class redefinition (e.g. javaagent,AOP代码植入的产生的instrumentation)
(4)Biased lock revocation 取消偏向锁
(5)Various debug operation (e.g. thread dump or deadlock check) dump 线程或者换一种方式表达:
(1)GC行为
(2)反优化行为
(3)部分JNI相关行为
(4)偏向锁相关行为
(5)调试行为(threaddump、heapdump、stacktrace等)
如何进入SafePoint
这是一个比较复杂的过程,JVM线程可能在处理不同的事务,处于不同的状态,为了能够让它们能够进入SafePoint,JVM设计了不同的机制。
| 线程状态 | 机制 |
|---|---|
| 解释执行中 | 修改解释器dispatch table,在下一条字节码执行前,强制检查SafePoint条件 |
| 本地方法代码段执行中 | 当线程从本地方法调用返回时,必须检查SafePoint条件 |
| 编译执行中 | JIT会在编译后的指令中插入检查点,检查点会进行SafePoint条件判断 |
| 阻塞中 | 已处于阻塞中,使线程保持阻塞状态即可 |
| 状态转换中 | 此时会等待线程完成状态转换后阻塞其自身 |
2.2 STW
Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。
STW是Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;STW多半是由于gc引起。
所有线程进入 SafePoint 等待的情况就是 Stop The World。比如,GC 时候一定需要所有线程同时进入 SafePoint,并停留在那里,等待 GC 处理完内存,再让所有线程继续执行。
2.3 偏向锁
偏向锁(biased locking)是一种优化机制,它使得一个线程在释放锁之后,vm仍旧在逻辑上让该线程"持有"一个对象的锁,它的优化前提点是该线程会在稍后重新获取该锁(这是一个常见的事件)。如果此时有其他线程争抢该锁,则必须撤消偏向锁持有者的偏向锁。
2.4 反优化
反优化(deoptimization)是一个将编译的(或者更优化的)栈桢转化为解释的(或者弱优化的)栈桢的过程。它也被解释为放弃依赖条件被打破(或者假定被打破)的nmethod的过程。反优化nmethod一般会被重新编译以便适配应用行为的变化。举个例子:编译器初始假定一个引用的值从不为null,并且使用"捕获内存访问"的方法进行测试。后续程序运行过程中,程序使用了null值,那么方法必须进行反优化和重编译,使用显示的test-and-branch方式发现此类null值。
2.5 代码缓存
它是一个特殊的持有编译后代码的堆,这些对象不会被gc搬移,但它们可能会包含服务于gc roots 的oops。
2.6 GC Root
垃圾收集根(garbage collection root),它是一个从外部指向java对象堆的指针.举例:从类的静态字段或活化栈桢的本地对堆中对象的引用。
2.7 JIT编译器
JIT编译器是一个应用运行时为应用(或类库)自生成代码的在线编译器。JIT即just in time.JIT编译器可以在java方法执行前非常快速地创建机器码。Hotspot编译器允许解释器执行java方法数千次以采样运行数据并热身,因为它可以在类加载初始化后观测到完整的类层级,热身周期使编译器有充足的依据做出优化决策。编译器也可以检视解释器收集的分支和类型的剖析信息。
2.8 JNI接口
java本地方法接口.它定义了一组api,用于java代码调用native c代码,以及它怎么调用java虚拟机代码。
2.9 oop
对象指针(oop),即object pointer,一般来说是一个指向gc管理堆的指针(这是一个传统的协议,o代表ordinary).它的实现是一个本地机器地址而不是一个句柄。对象指针可以由编译器或解释器java代码直接组装,因为gc知道这些代码中的对象指针的存活情况和位置。(参见gc映射)对象指针可以直接用c/c++代码来组装,但在跨越安全点时相应的代码一定要把它保持在每个句柄之内。
2.10 虚拟机操作
虚拟机操作(VM Operations),虚拟机中可以被java线程请求的,但是一定要由虚拟机线程以串行方式执行的操作,这些操作通常是同步的,因此请求者将会block直到虚拟机线程完成旧有操作。很多这些操作通常需要虚拟机到达安全点,gc是一个简单的例子。
1202

被折叠的 条评论
为什么被折叠?



