JAVA覆盖率统计之01-Jacoco控制流案例

字节码注入与控制流

1 注入方式
JaCoCo是一个被广泛使用的JAVA覆盖率统计工具,它利用ASM库,通过注入字节码的方式来修改和生成java字节码,从而记录程序的执行数据,但它不会改变原有代码的行为。 最常用的方式是通过Java Agent以On-The-Fly的方式在runtime来注入和统计数据。这种方式就不会改变编译的class文件。


implementation.png

当然在本文中,笔者将介绍Jacoco的具体注入方式,因此,我们使用Jaccoco Offline 的模式,在编译时直接将覆盖率统计的探针(Probe)注入(Inject)到被打桩的class文件中。

2 Probe探针组成
Jacoco是通过一个Probe探针的方式来注入的,探针是字节指令集插入到java方法中,程序执行后可以被记录,它不会改变原有代码的行为。
根据Jacoco官方介绍,一个Probe可以由以下JVM指令组成:

JVM指令 Probe作用 说明
ALOAD probearray 将一个引用类型本地变量推送至栈顶
xPUSH probeid 将一个常量值推送至栈顶
ICONST_1 将int型推送至栈顶
BASTORE 从操作数栈存存储到数组

根据代码逻辑的不同,可以由如下的一些变化:

Possible Opcodes Min. Size [bytes] Max. Size [bytes]
ALOAD_x, ALOAD * 1 2
ICONST_x, BIPUSH, SIPUSH, LDC, LDC_W ** 1 3
ICONST_1 1 1
BASTORE 1 1
Total: 4 7
  • The probe array is the first variable after the arguments. If the method arguments do not consume more that 3 slots the 1-byte opcode can be used.
    ** 1-byte opcodes for ids 0 to 5, 2-byte opcode for ids up to 127, 3-byte opcode for ids up to 32767. Ids values of 32768 or more require an additional constant pool entry. For normal class files it is very unlikely to require more than 32,000 probes.

感兴趣的读者可以阅读以下链接了解更多

https://www.jacoco.org/jacoco/trunk/doc/flow.html

3 Probe探针插入策略
JaCoCo是根据控制流Type来采用不同的探针插入策略的。探针不改变该方法的行为,但记录他们已被执行的事实,从理论上讲,可以在控制流图的每一个边插入一个探针,作为探针实现本身需要多个字节码指令,这将增加几倍的类文件的大小和执行速度。事实上,只需要一个几个探头,根据每个方法的控制流的方法。具体策略如下:

sequence.JPG

jump.JPG

return.JPG

案例

以下案例来介绍IF/FOR/抛异常等场景下jacoco是如何进行注入的。

package com.demo.jacoco;
public class DemoClass {
    public static void callIf(boolean flag) {
        print("start");
        if(flag) {
            print("true");
        }else {
            print("flase");
        }
        print("done");
    }
    private static void print(String string) {
        System.out.println(string);
    }
    
    public static void callFor(int loop) {
        for(int i=0;i<loop;i++)
            print("hi");
    }
    public static void callThrow(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们通过javap 来解析DemoClass.class

javap -v -c DemoClass.class

1 IF

![](https://upload-images.jianshu.io/upload_images/2651525-0a155f5b1d9281a4.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2 FOR

jacoco_for.JPG

3 Throw

jacoco_throw.JPG

4 默认构造方法

jacoco_1类构造方法.JPG
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 文章图片上传不正常,如需文档,可联系微信:1017429387 目录 1 安装... 4 1.1 配置探针... ...
    Mrhappy_a7eb阅读 6,593评论 0 5
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,200评论 19 139
  • 青春留给人们最美好的记忆莫过于出现在生命里那些形形色色的人,关于青春也往往就是去回忆那些熟悉又陌生的面孔,关于你那...
    七号灯塔阅读 262评论 0 0
  • 《海豚湾》是一部拍摄于2009年的纪录片,由路易·西霍尤斯执导,里克·奥巴瑞主演,该片记录了日本太地町当地的渔民...
    三岁就浪阅读 5,800评论 0 2
  • 我又路过昨天一起去的那家超市 空了的牙膏架又重新补上了货物 关于你去饭店的事情又害怕又支持 欣喜的是你可以不用半夜...
    縌偑_阅读 184评论 0 0