精华内容
下载资源
问答
  • JVM日志分析及工具

    千次阅读 2015-09-02 18:29:56
    JVM的GC日志的主要参数包括如下几个: -XX:+PrintGC 输出GC日志 -XX:+PrintGCDetails 输出GC的详细日志 -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式) -XX:+PrintGCDateStamps 输出GC的时间戳(以...

    JVM的GC日志的主要参数包括如下几个:

    -XX:+PrintGC 输出GC日志

    -XX:+PrintGCDetails 输出GC的详细日志

    -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)

    -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)

    -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息

    -Xloggc:../logs/gc.log 日志文件的输出路径

    在我做了如下的设置

    Java代码  收藏代码
    1. -XX:+PrintGCDetails -Xloggc:../logs/gc.log -XX:+PrintGCTimeStamps  

     

    以后打印出来的日志为:

    Java代码  收藏代码
    1. 0.756: [Full GC (System) 0.756: [CMS: 0K->1696K(204800K), 0.0347096 secs] 11488K->1696K(252608K), [CMS Perm : 10328K->10320K(131072K)], 0.0347949 secs] [Times: user=0.06 sys=0.00, real=0.05 secs]  
    2. 1.728: [GC 1.728: [ParNew: 38272K->2323K(47808K), 0.0092276 secs] 39968K->4019K(252608K), 0.0093169 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]  
    3. 2.642: [GC 2.643: [ParNew: 40595K->3685K(47808K), 0.0075343 secs] 42291K->5381K(252608K), 0.0075972 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]  
    4. 4.349: [GC 4.349: [ParNew: 41957K->5024K(47808K), 0.0106558 secs] 43653K->6720K(252608K), 0.0107390 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]  
    5. 5.617: [GC 5.617: [ParNew: 43296K->7006K(47808K), 0.0136826 secs] 44992K->8702K(252608K), 0.0137904 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]  
    6. 7.429: [GC 7.429: [ParNew: 45278K->6723K(47808K), 0.0251993 secs] 46974K->10551K(252608K), 0.0252421 secs]  

     

    我们取倒数第二条记录分析一下各个字段都代表了什么含义

    Java代码  收藏代码
    1. 5.617(时间戳): [GC(Young GC) 5.617(时间戳): [ParNew(使用ParNew作为年轻代的垃圾回收期): 43296K(年轻代垃圾回收前的大小)->7006K(年轻代垃圾回收以后的大小)(47808K)(年轻代的总大小), 0.0136826 secs(回收时间)] 44992K(堆区垃圾回收前的大小)->8702K(堆区垃圾回收后的大小)(252608K)(堆区总大小), 0.0137904 secs(回收时间)] [Times: user=0.03(Young GC用户耗时) sys=0.00(Young GC系统耗时), real=0.02 secs(Young GC实际耗时)]  

     

    我们再对数据做一个简单的分析

    从最后一条GC记录中我们可以看到 Young GC回收了 45278-6723=38555K的内存

    Heap区通过这次回收总共减少了 46974-10551=36423K的内存。

    38555-36423=2132K说明通过该次Young GC有2132K的内存被移动到了Old Gen,

     

    我们来验证一下

    在最后一次Young GC的回收以前 Old Gen的大小为8702-7006=1696

    回收以后Old Gen的内存使用为10551-6723=3828

    Old Gen在该次Young GC以后内存增加了3828-1696=2132K 与预计的相符


    ============================

    "Allocation Failure" is a cause of GC cycle to kick.

    "Allocation Failure" means what no more space left in Eden to allocate object. So, it is normal cause of young GC.

    意思是说没法分配更多的空间给Eden区

    • "[GC (Allocation Failure) ...]" - Header of the GC (Garbage Collection) message with the reason code "Allocation Failure" for the GC. So you can read this example as "A GC is performed because of Allocation Failure."

    Seeing GC Allocation Failure in GC logs is totally NORMAL and not a problem by itself.

    When using the Parallel GC collector/compactor, the Heap is split in between Young and Old spaces. GC Allocation failure is your case simply indicates the JVM reaches its max capacity of the YG space and now has to cleanup the short-lived objects or "garbage" from your Java application.

    This situation only becomes problematic is being executed too frequently and/or taking too much time to complete given it is a stop-the-world event.


    从以上解释来看Allocation Failure 只是代表年轻带不足,不是说GC产生了问题


    Gc日志分析工具

    (1)GCViewer

    https://github.com/chewiebug/GCViewer

    中文解释:http://www.cnblogs.com/o-andy-o/p/4058271.html


     

    其它监控方法

    Jvisualvm动态分析jvm内存情况和gc情况,插件:visualGC


      
    展开全文
  • 全网最硬核 JVM TLAB 分析 1. 内存分配思想引入 全网最硬核 JVM TLAB 分析 2. TLAB生命周期与带来的问题思考 全网最硬核 JVM TLAB 分析 3. JVM EMA期望算法与TLAB相关JVM启动参数 全网最硬核 JVM TLAB 分析 4. TLAB ...

    今天,又是干货满满的一天。这是全网最硬核 JVM 系列的开篇,首先从 TLAB 开始。由于文章很长,每个人阅读习惯不同,所以特此拆成单篇版和多篇版

    11. TLAB 相关 JVM 日志解析

    11.1. 准备 Java WhiteBox API

    首先需要准备好Java WhiteBox API

    11.1.1. 什么是 WhiteBox API

    WhiteBox API 是 HotSpot VM 自带的白盒测试工具,将内部的很多核心机制的 API 暴露出来,用于白盒测试 JVM,压测 JVM 特性,以及辅助学习理解 JVM 并调优参数。WhiteBox API 是 Java 7 引入的,目前 Java 8 LTS 以及 Java 11 LTS(其实是 Java 9+ 以后的所有版本,这里只关心 LTS 版本,Java 9 引入了模块化所以 WhiteBox API 有所变化)都是有的。但是默认这个 API 并没有编译在 JDK 之中,但是他的实现是编译在了 JDK 里面了。所以如果想用这个 API,需要用户自己编译需要的 API,并加入 Java 的 BootClassPath 并启用 WhiteBox API。

    11.1.2. WhiteBox API 如何实现的

    WhiteBox API 是一个 Java 类,位于 JDK 的测试包中,默认没有编译进标准发行版的 JDK 中

    test/lib/sun/hotspot/WhiteBox.java

    package sun.hotspot;
    public class WhiteBox {
      //仅举两个例子,省略其他 api 以及代码
      // Force Young GC
      public native void youngGC();
      // Force Full GC
      public native void fullGC();
    }
    

    可以看出,其实里面的所有 API 都是 JNI 调用,具体实现是:

    src/hotspot/share/prims/whitebox.cpp

    WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
      Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(true);
      Universe::heap()->collect(GCCause::_wb_full_gc);
    #if INCLUDE_G1GC
      if (UseG1GC) {
        // Needs to be cleared explicitly for G1
        Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(false);
      }
    #endif // INCLUDE_G1GC
    WB_END
    
    WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o))
      Universe::heap()->collect(GCCause::_wb_young_gc);
    WB_END
    
    {CC"youngGC",  CC"()V",                             (void*)&WB_YoungGC },
    {CC"fullGC",   CC"()V",                             (void*)&WB_FullGC },
    
    //省略其他代码
    

    可以看出,JNI 调用实现直接调用了底层 JVM 的相关接口,相当于把 JVM 的一些关键机制暴露出来,用于白盒测试。但是如之前所说,JDK 发行版没有包括 test 下的测试代码,也就是 WhiteBox API 所在的 jar 包并没有打进默认的 JDK 中。这就需要我们自己编译一下这个代码。

    11.1.3. 什么是 BootClassPath

    Java 内有三种不同的类加载器:应用类加载器(application classloader),扩展类加载器(extension classloader)还有根类加载器(bootstrap classloader)

    • 应用类加载器,加载我们classpath目录下的所有类文件
    • 扩展类加载器,加载标准 Java 类库扩展的类,就是你的jre目录下的/lib/ext目录下的所有类
    • 根类加载器(bootstrap classloader),扫描 BootClassPath 下的 标准 Java 类库的类加载器。标准 Java 类库限制了一些包路径的类,必须通过根类加载器加载。

    对于 WhiteBox API,由于是他的包为sun.hotspot,普通的类加载器是不能加载这个包路径的类的,需要通过根类加载器加载。

    11.1.4. 怎么指定 BootClassPath

    在 Java 8,通过 -Xbootclasspath: 或者 -Xbootclasspath/p:指定,例如:

    -Xbootclasspath:/home/project/whitebox.jar
    -Xbootclasspath/p:/home/project/whitebox.jar
    

    在 Java 9 之后的版本,这两个参数已经过期了,需要改成-Xbootclasspath/a:,例如:

    -Xbootclasspath/a:/home/project/whitebox.jar
    

    否则会报错-Xbootclasspath is no longer a supported option.

    这里对应的 JDK 源码是:
    src/hotspot/share/runtime/arguments.cpp

    // -bootclasspath:
    } else if (match_option(option, "-Xbootclasspath:", &tail)) {
        jio_fprintf(defaultStream::output_stream(),
          "-Xbootclasspath is no longer a supported option.\n");
        return JNI_EINVAL;
    // -bootclasspath/a:
    } else if (match_option(option, "-Xbootclasspath/a:", &tail)) {
      //将参数添加到 bootclasspath 中
      Arguments::append_sysclasspath(tail);
    // -bootclasspath/p:
    } else if (match_option(option, "-Xbootclasspath/p:", &tail)) {
        jio_fprintf(defaultStream::output_stream(),
          "-Xbootclasspath/p is no longer a supported option.\n");
        return JNI_EINVAL;
    }
    

    11.1.5. 使用 WhiteBox API

    1. 编译 WhiteBox API

    https://github.com/openjdk/jdk/tree/master/test/lib路径下的sun目录取出,编译成一个 jar 包,名字假设是 whitebox.jar

    2. 编写测试程序

    whitebox.jar 添加到你的项目依赖,之后写代码

    public static void main(String[] args) throws Exception {
            WhiteBox whiteBox = WhiteBox.getWhiteBox();
            //获取 ReservedCodeCacheSize 这个 JVM flag 的值
            Long reservedCodeCacheSize = whiteBox.getUintxVMFlag("ReservedCodeCacheSize");
            System.out.println(reservedCodeCacheSize);
            //打印堆内存各项指标
            whiteBox.printHeapSizes();
            //执行full GC
            whiteBox.fullGC();
            
            //保持进程不退出,保证日志打印完整
            Thread.currentThread().join();
    }
    

    3. 启动程序查看效果

    使用启动参数 -Xbootclasspath/a:/home/project/whitebox.jar -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xlog:gc 启动程序。其中前三个 Flag 表示启用 WhiteBox API,最后一个表示打印 GC info 级别的日志到控制台。

    我的输出:

    [0.025s][info][gc] Using G1
    251658240
    Minimum heap 8388608 Initial heap 268435456 Maximum heap 4276092928 Space alignment 2097152 Heap alignment 2097152
    [0.899s][info][gc] GC(0) Pause Full (WhiteBox Initiated Full GC) 5M->0M(20M) 45.183ms
    

    至此,我们就准备好了 WhiteBox 调试环境

    11.2. 测试 TLAB 查看日志

    编写测试代码:

    //对于字节数组对象头占用16字节
    private static final int BYTE_ARRAY_OVERHEAD = 16;
    //我们要测试的对象大小是100kb
    private static final int OBJECT_SIZE = 100 * 1024;
    //需要使用静态field,而不是方法内本地变量,否则编译后循环内的new byte[]全部会被省略,只剩最后一次的
    public static byte[] tmp;
    
    public static void main(String[] args) throws Exception {
            WhiteBox whiteBox = WhiteBox.getWhiteBox();
            //强制 fullGC 防止接下来程序发生 GC
            //同时可以区分出初始化带来的其他线程的TLAB相关的日志
            whiteBox.fullGC();
            //分配对象,大小1KB
            for (int i = 1; i < 512; ++i) {
                tmp = new byte[OBJECT_SIZE - BYTE_ARRAY_OVERHEAD];
            }
            //强制 fullGC,回收所有 TLAB
            whiteBox.fullGC();
            //分配对象,大小100KB
            for (int i = 1; i < 500; ++i) {
                tmp = new byte[OBJECT_SIZE * 100 - BYTE_ARRAY_OVERHEAD];
            }
            whiteBox.fullGC();
            //阻塞程序,保证所有日志输出完
            Thread.currentThread().join();
        }
    

    之后,我们以如下的启动参数(前三个启动参数是我们前面章节提到的启用 WhiteBox API 需要的参数)启动这个程序,查看日志(关于日志配置,请参考之前的章节)。

    -Xbootclasspath/a:./jdk-white-box-17.0-SNAPSHOT.jar
    -XX:+UnlockDiagnosticVMOptions
    -XX:+WhiteBoxAPI
    -Xms512m
    -Xmx512m
    -XX:+UseTLAB
    -Xlog:gc+tlab=trace
    -Xlog:gc
    

    可以看到下面类似的日志,我们来根据代码分析下,首先是运行到第一个 fullGC 结束之前的所有日志,首先是 JVM 启动的时候会输出用的是什么 GC 的日志,这里是默认的 G1:

    [0.022s][info][gc] Using G1
    

    还会输出 TLAB 的通用配置:

    [0.030s][trace][gc,tlab] TLAB min: 328 initial: 60293 max: 65536
    

    也就是这里 TLAB 最小为 328 MarkWordSize,初始为 60293 MarkWordSize,最大为 65536 MarkWordSize。默认的 64位 JVM 的 MarkWordSize 为 8 字节,也就是堆内存 8 字节对齐。

    然后,由于 JVM 启动时,默认会初始化很多线程,包括:

    • main 线程:执行 main 方法的线程
    • Attach listener 线程:Attach Listener 线程是负责接收到外部的命令,而对该命令进行执行的并且把结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。 如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。
    • Signal Dispatcher线程:Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather 线程去进行分发到各个不同的模块处理命令,并且返回处理结果。 signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。
    • Reference Handler 线程:JVM在创建main线程后就创建Reference Handler线程,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题 。
    • Finalizer线程:这个线程也是在main线程之后创建的,主要用于在垃圾收集前,调用对象的finalize()方法。
    • DestroyJavaVM线程:执行main()的线程在main执行完后调用JNI中的 jni_DestroyJavaVM() 方法唤起DestroyJavaVM 线程,它将在虚拟机中所有其它非守护线程全部结束后销毁虚拟机。

    在运行过程中,根据你的JIT编译配置,GC参数,还会有:

    • CompilerThread 线程:JIT编译相关线程,主要是负责 C1 C2 即时编译以及 OSR(On stack Replacement) 替换等任务
    • GC 相关线程:执行GC任务的线程

    除了这些之外,Java 8 之后 ForkJoinPool 还会创建一个默认大小为 cpu 核数 -1 的线程池:CommonForkJoinPool,是用来处理 ParallelStream 的默认线程池还有 Future 框架 CompletableFuture 的默认线程池。

    这些线程中的一部分会在 JVM 初始化的时候创建一些对象使用,那么就肯定会涉及到 TLAB,所以会有如下日志:

    [0.042s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(2) returns 65536
    [0.042s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     1024KB refills: 1 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.155s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(25) returns 65536
    [0.155s][trace][gc,tlab] TLAB: fill thread: 0x000002a60028e900 [id: 15380] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     1024KB refills: 1 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.340s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(2) returns 256
    [0.340s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     2048KB refills: 2 waste  0.1% gc: 0B slow: 576B fast: 0B
    
    
    //省略其他线程的 TLAB 日志,这里 23480 是 Main 线程。读者可以通过程序输出日志中执行循环分配对象的线程 TLAB 日志判断哪一个是 Main 线程
    

    其中,[0.042s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(2) returns 65536的对应的就是调用了compute_size计算初始 TLAB 大小,传入的 2 就是当前这个线程分配的对象所需的大小(MarkWordSize),计算出初始大小为 65536,因为 MarkWordSize = 8 所以 就是 65536*8=524288 字节,也就是 512 KB。下一行日志,代表这个线程初始化申请一块内存作为 TLAB 了,[0.042s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0 refill waste: 8192B alloc: 1.00000 1024KB refills: 1 waste 0.0% gc: 0B slow: 0B fast: 0B,这个 TLAB 的信息包括:

    • 线程号 0x000002a66a471710 [id: 12916]
    • 期望大小,就是刚刚计算出来的 512KB:desired_size: 512KB
    • 慢分配次数,就是不在当前 TLAB 直接分配的分配次数:slow allocs: 0
    • 当前浪费空间限制,也就是重新申请 TLAB 造成的浪费限制大小,refill waste: 8192B,也就是最多能浪费 8192 字节
    • 当前 _allocation_fraction 相关信息,alloc: 1.00000 1024KB,代表当前 _allocation_fraction 是 1.00000,TLAB 一共用了 1024 KB
    • 发生 refills 重新申请 TLAB 的次数:refills: 1
    • 浪费比例:waste 0.0%
    • GC 回收造成的浪费大小:gc: 0B
    • refill造成的浪费:slow: 0B
    • refill造成的浪费:fast: 0B

    我们这里来计算下为何当前浪费空间为 8192 字节,也就是 8KB。TLABRefillWasteFraction 我们并没有修改,也就是默认的 64,那么初始的最大浪费空间 = TLAB 大小 / TLABRefillWasteFraction,也就是 512KB / 64 = 8KB

    第一次强制 FullGC 之后,看到如下相关日志:

    //首先输出了每一个线程的当前 TLAB 的信息
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 15 waste  7.1% gc: 360616B slow: 13880B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a60028d180 [id: 24604] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a60028e900 [id: 15380] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 1 waste 99.9% gc: 524008B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a6002dc380 [id: 10316] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600319040 [id: 3856] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a60031a1f0 [id: 16808] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600326970 [id: 292] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600328620 [id: 10932] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a60032ac90 [id: 14528] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 1 waste 99.8% gc: 521328B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600343ec0 [id: 20040] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600ca03f0 [id: 14304] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600e157e0 [id: 24148] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 1 waste 60.9% gc: 1248B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600f17090 [id: 13736] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 1 waste 99.9% gc: 523976B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a600f0e850 [id: 19208] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 1 waste 99.9% gc: 521688B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a601381710 [id: 9804] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a6013aef00 [id: 23640] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a6013f7650 [id: 1860] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a601ad77b0 [id: 17292] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 1 waste 99.9% gc: 521752B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a601971200 [id: 17448] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a601972220 [id: 11844] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.915s][trace][gc,tlab] GC(0) TLAB: gc thread: 0x000002a601705560 [id: 7832] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     8192KB refills: 0 waste  0.0% gc: 0B slow: 0B fast: 0B
    //GC TLAB 统计
    [0.915s][debug][gc,tlab] GC(0) TLAB totals: thrds: 7  refills: 21 max: 15 slow allocs: 0 max 0 waste: 38.0% gc: 2974616B max: 524008B slow: 13880B max: 13880B fast: 0B max: 0B
    //每个线程 TLAB 期望大小的变化
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a66a471710 [id: 12916] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a60028d180 [id: 24604] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a60028e900 [id: 15380] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a6002dc380 [id: 10316] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600319040 [id: 3856] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a60031a1f0 [id: 16808] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600326970 [id: 292] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600328620 [id: 10932] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a60032ac90 [id: 14528] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600343ec0 [id: 20040] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600ca03f0 [id: 14304] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600e157e0 [id: 24148] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600f17090 [id: 13736] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a600f0e850 [id: 19208] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a601381710 [id: 9804] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a6013aef00 [id: 23640] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a6013f7650 [id: 1860] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a601ad77b0 [id: 17292] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a601971200 [id: 17448] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a601972220 [id: 11844] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    [0.980s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a601705560 [id: 7832] refills 50  alloc: 1.000000 desired_size: 65536 -> 65536
    //GC 信息
    [0.980s][info ][gc     ] GC(0) Pause Full (WhiteBox Initiated Full GC) 7M->0M(512M) 65.162ms
    

    首先是输出了每一个线程的当前 TLAB 的信息。与前面发生 refill 分配 TLAB 时相似。只不过多了 GC 全局序号,从 0 开始, GC(0) 代表的就是第一次 GC 相关的日志
    然后是 GC TLAB 统计:[0.915s][debug][gc,tlab] GC(0) TLAB totals: thrds: 7 refills: 21 max: 15 slow allocs: 0 max 0 waste: 38.0% gc: 2974616B max: 524008B slow: 13880B max: 13880B fast: 0B max: 0B

    • 一共有7个线程用了 TLAB:thrds: 7,也就是前面带 GC(0) 的 TLAB 信息日志中,只有 7 个线程的 refills 是大于 0 的。
    • 本次 GC 所有线程 refills 的次数 refills: 21
    • 历史最大的某次 GC 内 refills 的次数 max: 15
    • 本次 GC 所有线程慢分配的次数 slow allocs: 0
    • 历史最大的某次 GC 内慢分配的次数 max: 0
    • 本次 GC 所有线程 TLAB 内存浪费比例 waste: 38.0%
    • 各种浪费内存大小:`gc: 2974616B max: 524008B slow: 13880B max: 13880B fast: 0B max: 0B``

    接着打印了每个线程 TLAB 期望大小的变化:[0.979s][trace][gc,tlab] GC(0) TLAB new size: thread: 0x000002a66a471710 [id: 12916] refills 50 alloc: 1.000000 desired_size: 65536 -> 65536,这里还是 MarkWordSize 而不是实际字节大小。
    最后是本次 GC 信息:[0.980s][info ][gc ] GC(0) Pause Full (WhiteBox Initiated Full GC) 7M->0M(512M) 65.162ms,代表是 FullGC,并且是 WhiteBox 触发的,堆内存使用从 7M 回收到了 0M,堆内存总大小是 512M,一共停顿时间是 65.162 ms。

    之后我们的程序申请了 512 个大小为 1KB 的对象。为何new byte[OBJECT_SIZE - BYTE_ARRAY_OVERHEAD]大小是 1KB 呢?因为数组对象头默认是 16 字节,所以再加上 1012 个 byte 就是 1KB。循环结束后,输出了下面两行日志:

    [0.989s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(128) returns 65536
    [0.989s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     1024KB refills: 1 waste  0.0% gc: 0B slow: 0B fast: 0B
    [0.989s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(128) returns 65536
    [0.989s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     1024KB refills: 2 waste  0.1% gc: 0B slow: 1024B fast: 0B
    

    可以看出是发生了两次 refill,第一次是线程第一次创建对象时申请的,第二次是申请到第 512 个对象,TLAB 大小是 512 KB,之前的 511KB 已经被占用了,根据前一篇的 TLAB 原理分析,我们知道由于需要填充 dummy objects 所以要保留一个数组对象头的大小,所以剩下可分配的空间其实不足 1KB,所以需要 refill。并且,浪费的空间(1KB)小于当前浪费空间限制(8KB),所以可以重新申请新的 TLAB 进行分配

    然后我们的程序在 FullGC 之后,继续申请了 200 个大小为 100KB 的大对象。这里我们忽略 GC 相关日志,只看分配对象的时候产生的日志。

    [3036.734s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(12800) returns 65536
    [3036.734s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 0  refill waste: 8192B alloc: 1.00000     1024KB refills: 1 waste  0.0% gc: 0B slow: 0B fast: 0B
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1028
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1032
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1036
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1040
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1044
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1048
    //省略中间分配日志。。。
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1452
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1456
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1460
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1464
    [3047.279s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(12800) returns 65536
    [3047.279s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 110  refill waste: 11712B alloc: 1.00000    13312KB refills: 2 waste  1.2% gc: 0B slow: 12288B fast: 0B
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1028
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1032
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1036
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1040
    //省略中间分配日志。。。
    [3047.281s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1340
    

    100KB 的对象,换算成 MarkWordSize 就是 12800,对应日志:[3036.734s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(12800) returns 65536,本次计算 TLAB 大小依然是 65536 MarkWordSize,也就是 512KB。在分配第五个对象开始, TLAB 的剩余内存就不够了。但是初始最大浪费空间是 8KB,所以只能直接在 Eden 区分配,并根据 TLABWasteIncrement(默认为 4) 设置的值递增最大浪费空间,也就是每次递增 4 * MarkWordSize 也就是 32 字节。体现在了日志:

    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1028
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1032
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1036
    [3047.276s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1040
    

    可以看出,每次 TLAB 外分配都让最大浪费空间限制加 4。当剩余空间小于最大浪费空间限制时,线程 refill 申请了一块新的 TLAB 进行分配:

    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1456
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1460
    [3047.279s][trace][gc,tlab] TLAB: slow thread: 0x000002a66a471710 [id: 12916] obj: 12800 free: 1464 waste: 1464
    [3047.279s][trace][gc,tlab] ThreadLocalAllocBuffer::compute_size(12800) returns 65536
    [3047.279s][trace][gc,tlab] TLAB: fill thread: 0x000002a66a471710 [id: 12916] desired_size: 512KB slow allocs: 110  refill waste: 11712B alloc: 1.00000    13312KB refills: 2 waste  1.2% gc: 0B slow: 12288B fast: 0B
    

    至此,我们就分析了基本所有 TLAB 相关的日志。

    展开全文
  • JVM日志示例分析

    千次阅读 2014-10-30 21:00:37
    引言: JVM分析和优化是Java技术体系中的高大上的内容,其实这个东西没有那么神秘和高深,只是大部分童鞋没有机会真正接触它们,从而对它们有一个深入理解。这里通过一个小题目,来展示如何来看JVM输出的日志信息,...

    引言: JVM分析和优化是Java技术体系中的高大上的内容,其实这个东西没有那么神秘和高深,只是大部分童鞋没有机会真正接触它们,从而对它们有一个深入理解。这里通过一个小题目,来展示如何来看JVM输出的日志信息,并得出JVM几个设置变量的设置信息。


    1. 题目的提出,请分析最有可能的JVM的参数设置。

    Heap

     def new generation   total 6464K, used 115K [0x34e80000,0x35580000, 0x35580000)

     eden space 5760K,   2% used[0x34e80000, 0x34e9cd38, 0x35420000)

     from space 704K,   0% used[0x354d0000, 0x354d0000, 0x35580000)

     to   space 704K,   0% used [0x35420000, 0x35420000, 0x354d0000)

     tenured generation   total 18124K, used 8277K [0x35580000,0x36733000, 0x37680000)

      the space 18124K,  45% used[0x35580000, 0x35d95758, 0x35d95800, 0x36733000)

     compacting perm gen  total 16384K, used 16383K [0x37680000,0x38680000, 0x38680000)

      the space 16384K,  99% used[0x37680000, 0x3867ffc0, 0x38680000, 0x38680000)

       ro space 10240K,  44% used[0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)

        rw space 12288K,  52% used [0x39080000, 0x396cdd28, 0x396cde00,0x39c80000)

    2.  JVM参数分析 

       2.1 -XX:+PrintGCDetails
        由于JVM需要打印出详细的GC回收和内存分布信息,故需要设置此变量

       2.2  -Xmx 最大堆空间设置

        def new generation为新生代的信息, tenured generation 代表的是年老代的信息。 其目前使用分配空间为6M.  [0x34e80000,0x35580000, 0x35580000): 分别代表最小地址,当前分配的空间地址,最大的空间地址。当前使用的空间是6M + 18M = 24M.

         由于x34e80000~~0x376800000之间分配的空间为40M,故当前的分配的空间不是设置的最大空间值,所以可知其设置了最大的内容空间,而且其最大空间xmx和最小空间xms不是一致的。

         故其-Xmx40M. 其无法得知是否已经设置xmx。

       2.3  -Xmn年轻带空间设置

           分析def new generation的信息,当前内存使用情况6464k,  eden space 5760k,  from/to space: 704k. 其最大空间地址和当前的地址空间位置一样:0x35580000,但是目前使用的内存并未完全使用完毕,故可推测知道,其设置年轻带的内存大小。

           其最大空间地址0x35580000 -  最小空间地址0x34e80000 = 7M.  故其-Xmn为7M.

      2.4 maxpermsize
            compacting perm gen表示永久代的信息,存放class信息,静态方法和变量,常量信息等。 其最大空间地址和当前空间地址一样,故可知其内存已经被全部分配了。另外,从使用率99%可知,基本使用完毕了。

           其最大空间地址0x38680000  - 最小空间地址0x37680000 = 16.7M. 故可知其最大的PermSize已经设置过了,但无法得知其初始设置的permsize大小。

            -XX:maxpermsize=17M.

    3.  总结

        以上的文本示例来自于JVM中的内存分配片段,通过以上的分析,可以帮助大家来了解当前的内存状态信息,从而可以利用以上信息,来进行JVM的优化和调优。

        JVM参数: -Xmx40M -Xmn7M    -XX:maxpermsize=17M -XX:+PrintGCDetails verbose:gc


          

         

     

    展开全文
  • JVM OOM日志分析

    2021-01-21 20:50:34
    gc日志分析如下: 2019-03-28T18:02:49.809+0800: 3.175: [GC (Allocation Failure) [ParaNew: 65536K->7435K(76288K)] 65536K->7451K(251392K), 0.0132004 secs] [Times: user=0.00 sys=0.02, real=0.0.

    最近项目出现OOM,复习一下知识:

     

    1. 首先,jvm增加参数,打印printGCdetails的日志
    2. 运行过程中,观察gc日志

    gc日志分析如下:

    2019-03-28T18:02:49.809+0800: 3.175: [GC (Allocation Failure) [ParaNew: 65536K->7435K(76288K)] 65536K->7451K(251392K), 0.0132004 secs] [Times: user=0.00 sys=0.02, real=0.01 secs] 

    日志格式基本如上图所示,解释一下含义:

    • 2019-03-28T18:02:49.809+0800  : gc日志记录时间
    • 3.175 :gc发生时,虚拟机运行了多少秒
    • GC (Allocation Failure) : 发生了一次垃圾回收,若前面有Full则表明是Full GC,没有Full的修饰表明这是一次Minor GC 。注意它不表示只GC新生代,括号里的内容是gc发生的原因,这里的Allocation Failure的原因是年轻代中没有足够区域能够存放需要分配的数据而失败,。
    • ParaNew: 使用的垃圾收集器的名字。
    • 65536K->7435K(76288K) :垃圾收集前后的年轻代内存使用情况,其中前面的65536kb为gc之前的使用量,7435kb为gc之后的内存使用量。括号里的76288k为该内存区域的总量。 
    •  65536K->7451K(251392K) : 垃圾收集前后整个堆内存的使用情况,括号里的为整个可以的堆内存的容量。
    • 0.0132004 secs :整个GC过程持续时间
    • [Times: user=0.00 sys=0.02, real=0.01 secs] :分别表示用户态耗时,内核态耗时和总耗时。也是对gc耗时的一个记录
    展开全文
  • JVM GC日志分析

    千次阅读 2019-03-19 19:44:02
    之前一篇博客对GC日志做了简单分析,主要偏重算法的说明,这次作为补充说明,偏重一点GC日志分析说明及查看GC日志工具的使用,工具有多种,找到自己使用较顺手的一种即可。 GC(Garbage Collection),即垃圾回收...
  • JVM Crash日志分析

    2016-01-22 10:28:21
    JVM Crash日志分析 转自:http://book.51cto.com/art/201408/448846.htm 8.7.3 JVM Crash日志分析(1) JVM有时也会因为一些原因而导致直接垮掉,因为JVM本身也是一个正在运行的程序,这个程序本身也会有很多...
  • JVM GC日志文件分析

    2020-04-24 22:26:34
    JVM GC日志文件分析        GC 是垃圾回收(Garbage Collection)的缩写。两个关键名词:垃圾、回收。那何谓垃圾呢,JVM认为没有任何引用指向的对象就是垃圾对象,JVM里面判定为垃圾的算法有:...
  • jvm GC日志分析详解

    千次阅读 2018-05-18 11:36:59
    JVM和GC调优,总结下CMS的一些特点和要点,让我们先简单的看下整个堆年轻代和年老代的垃圾收集器组合(以下配合java8完美支持,其他版本可能稍有不同),其中标红线的则是我们今天要着重讲的内容:垃圾回收器的可用...
  • JVM crash 错误日志分析

    2012-03-14 10:36:42
    JVM crash 错误日志分析
  • 文章目录参考JVM 调优指标JVM 日志JVM 调优工具 参考 https://blog.csdn.net/weixin_42447959/article/details/81637909 JVM 调优指标 内存占用:程序正常运行需要的内存大小。 延迟:由于垃圾收集而引起的程序停顿...
  • JVM崩溃日志分析1

    万次阅读 多人点赞 2016-03-14 16:37:18
    最先线上的一个tomcat总是无缘无故崩溃,tomcat日志里又没有报任何错误,于是调出JVM的崩溃日志查看,一般崩溃日志在启动目录下,比如tomcat的bin目录下,但是如果你用自己写的脚本启动的tomcat,则这个日志可能就在...
  • 全网最硬核 JVM TLAB 分析 1. 内存分配思想引入 全网最硬核 JVM TLAB 分析 2. TLAB生命周期与带来的问题思考 全网最硬核 JVM TLAB 分析 3. JVM EMA期望算法与TLAB相关JVM启动参数 全网最硬核 JVM TLAB 分析 4. TLAB ...
  • jvm的GC日志分析

    万次阅读 2015-06-22 16:37:38
    JVM的GC日志的主要参数包括如下几个: -XX:+PrintGC 输出GC日志 -XX:+PrintGCDetails 输出GC的详细日志 -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式) -XX:+PrintGCDateStamps 输出GC的时间戳(以...
  • 重新认知JVM:  通过前面从Class文件到类装载器,再到运行时数据区的过程。我们画张图展示了JVM的大体物理结构图。 GC优化:  内存被使用了之后,难免会有不够用或者达到设定值的时候,就需要对内存空间进行垃圾...
  • JVM 之 GC日志分析

    万次阅读 2016-07-21 17:53:57
    分析gc日志后,经常需要调整jvm内存相关参数,常用参数如下 -Xms:初始堆大小,默认为物理内存的1/64(;默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制 -Xmx:最大堆...
  • 记一次JVM GC日志分析

    万次阅读 2011-09-29 22:30:34
    这几天在准备升级JDK版本到1.6,对目前线上JVM(版本是1.5.0_08-b03) GC日志进行了分析,发现一些参数设置不太合理的地方,有待后续通过数据来进行验证。 1.原始GC日志(通过JVM配置GC Print参数获取GC日志) ......
  • 全网最硬核 JVM TLAB 分析 1. 内存分配思想引入 全网最硬核 JVM TLAB 分析 2. TLAB生命周期与带来的问题思考 全网最硬核 JVM TLAB 分析 3. JVM EMA期望算法与TLAB相关JVM启动参数 全网最硬核 JVM TLAB 分析 4. TLAB ...
  • 分析JVM gc日志

    2016-04-29 10:03:40
    GC日志是一种很重要的日志,它虽然无法定位出很详细的内容,但反映出JVM整体的运行状况。以生产环境为例:在出现严重性能问题时,整个系统卡住了,我发现1分钟之内full gc是25次,当把问题解决之后,1分钟的full gc...
  • 全网最硬核 JVM TLAB 分析 1. 内存分配思想引入 全网最硬核 JVM TLAB 分析 2. TLAB生命周期与带来的问题思考 全网最硬核 JVM TLAB 分析 3. JVM EMA期望算法与TLAB相关JVM启动参数 全网最硬核 JVM TLAB 分析 4. TLAB ...
  • 许多事件都可能会导致JVM暂停所有的应用线程。这类暂停又被称为”stop-the-world”(STW)暂停。触发STW暂停最常见的原因就是垃圾回收了(github中的一个例子),但不同的JIT活动(例子),偏向锁擦除(例子),特定的...
  • 全网最硬核 JVM TLAB 分析 1. 内存分配思想引入 全网最硬核 JVM TLAB 分析 2. TLAB生命周期与带来的问题思考 全网最硬核 JVM TLAB 分析 3. JVM EMA期望算法与TLAB相关JVM启动参数 全网最硬核 JVM TLAB 分析 4. TLAB ...
  • 这是jvm发生异常时产生异常日志文件的默认格式:hs_err_pid**.log文件。 文件内部的信息肯定能帮助我们发现一些端倪,但是由于我水平有限一点也看不懂就在网上查找如何看jvm的异常日志。就发现两个大佬的博客写的都...
  • 全网最硬核 JVM TLAB 分析 1. 内存分配思想引入 全网最硬核 JVM TLAB 分析 2. TLAB生命周期与带来的问题思考 全网最硬核 JVM TLAB 分析 3. JVM EMA期望算法与TLAB相关JVM启动参数 全网最硬核 JVM TLAB 分析 4. TLAB ...
  • JVM故障分析系列

    2019-08-30 17:29:02
    JVM故障分析系列之二:jstack生成的Thread Dump日志结构解析 JVM故障分析系列之三:jstat命令的使用及VM Thread分析 JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态 JVM故障分析系列之五:常见的Thread ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 74,238
精华内容 29,695
关键字:

jvm日志分析