jacoco底层原理解析

阅读本文前,建议先了解以下相关知识:

  1. JVM字节码
  2. java动态代理
  3. Java字节码插桩技术
  4. Java字节码操作框架ASM:史上最通俗易懂的ASM教程

Jacoco使用插桩的方式来记录覆盖率数据,是通过一个probe探针来注入。

一、覆盖率分析机制

有几种不同的方法来收集覆盖率信息。对于每种方法,由不同的实现技术,黄色路径是jacoco推荐的方式,即通过字节码插桩实现代码覆盖率的统计:

 

在ByteCode字节码上插桩模式有两种:

1. on-the-fly模式

JVM通过 -javaagent参数指定jar文件启动代理程序,代理程序在ClassLoader装载一个class前判断是否修改class文件,并将探针插入class文件,探针不改变原有方法的行为,只是记录是否已经执行。

2. offline模式

在测试之前先对文件进行插桩,生成插过桩的class或jar包,测试插过桩的class和jar包,生成覆盖率信息到文件,最后统一处理,生成报告。

二、jacoco插桩策略

参考文章:Java方法的控制流分析

1、Java字节码的控制流程图

要实现对代码的覆盖率统计,首先要了解方法的内部控制流。以下面这段java代码为例

public static void example() {
    a();
    if (cond()) {
        b();
    } else {
        c();
    }
    d();
}

编译之后的字节码如下(.class文件中保存的就是字节码):

public static example()V
      INVOKESTATIC a()V
      INVOKESTATIC cond()Z
      IFEQ L1
      INVOKESTATIC b()V
      GOTO L2
  L1: INVOKESTATIC c()V
  L2: INVOKESTATIC d()V
      RETURN

控制流通过有条件或无条件操作码之类的跳转指令 来实现。跳转目标在技术上是相对于目标指令的相对偏移。为了提高可读性,我们改用符号标签(ASM API也使用此类符号标签,IFEQ L1 GOTO L2):

上面字节码的控制流程可以用流程图表示。节点是字节码指令,边表示指令之间的控制流。该示例的控制流显示在该图的左框中:

2、探针插入策略

探针就是可以插入现有指令之间的一段其他指令,它们不会改变方法的行为,但是会记录它们已被执行的事实。

jacoco插桩并不是每行,探针实现本身需要多个字节码指令,因此这将使类文件的大小增加数倍,并显着降低所检测类的执行速度。实际上,根据方法的控制流程,每个方法仅需要几个探针,具体策略如下:

  • 在每个方法出口处(返回或抛出)插入探针
  • 具有多条指向边的目标指令的多条指向边上

二、jacoco原理

Jacoco on-the-fly 模式通过jacoco agent在类加载时对原始类进行插桩,得到插桩后的类。正常class文件加载流程如下:

被jacoco代理的class文件加载流程

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值