内存分析之日志

日志分析


日志举例一

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)数值转化为了字节而已。需要重点关注的是以下两类:

    1. 意义一样名字有变化

      -XX:InitialHeapSize 对应启动参数里的 -Xms

      -XX:MaxHeapSize 对应启动参数里的 -Xmx

    2. 启动参数里没有设置的但是这里出现的

      例如:-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() 退出。

  1. VM Thread退出时:JVM即将关闭,此时会进入SafePoint,进行退出前的检查,并等待native thread执行完毕,最终关闭整个JVM。(此时只有begin,没有end,因为JVM已经要关闭了)

  2. 处理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是一个简单的例子。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值