Android自动化埋点(一) - JVM字节码

JVM字节码

开头

这一系列文章,主要是讲自动化埋点又叫无痕埋点,或者字节码插桩技术,写这个系列文章的目的是 偶然间发现,网上关于这方面的博客很少,所以我根据自己的一些实战经验,整理了这个系列的文章。

整个系列不会讲的太深入,以免造成初学者不知所云,通过一个Demo,让大家了解 java 字节码插桩的基本实现原理,为后续更深入的学习指引方向。

一. 概要

本篇主要是对Java栈,栈帧,局部变量表,操作数栈等进行一定讲解,结合实际demo和字节码文件,了解jvm虚拟机是如何执行我们的Java程序的。
JVM作为基础,是进行字节码插桩所必须要掌握的知识,但是本篇不会进行太深入的讲解,以免初学者陷入细节无法自拔或者不知所云。

二. JVM内存分区

在这里插入图片描述
Java 是以方法为执行单位,而我们的字节码插桩也主要是关心JAVA栈

三. 栈帧的组成

在这里插入图片描述
每创建一个线程就会对应创建一个Java栈,所以Java栈也是"线程私有"的内存区域,而这个栈对应也会包含很多栈帧,每调用一个方法时,都会向Java栈中压入一个栈帧。
每个栈帧中包含:

  1. 局部变量表:主要是存放参数和方法内本地变量
  2. 操作数栈: 存储方法内加载的数据和进行字节码指令操作
  3. 动态链接: 指向运行时常量池的方法引用
  4. 方法返回地址: 方法正常退出或者异常退出的定义

四. 局部变量表和操作数栈

  • 虚拟机栈遵循先进后出原则
  • 局部变量表我们暂且可以把它理解为一个数组,我们通过数组索引取对应的元素

定义一个test静态方法,无返回值,方法需传入一个参数,方法体内是简单的数值相加

public class TestByteCode {
    
    public static void main(String[] args) {
        test(5);
    }

    public static void test(int num) {
        int a = 1;
        int c = a + num;
    }
}

编译后的java字节码

(* 查看字节码文件,大家可以在Android studio 上安装ASM Bytecode Viewer插件)

  public static void test(int a) { 
    iconst_1  
    istore 1
    iload 1
    iload 0
    iadd
    istore 2
    return
  }
下面是详细分析字节码中每一个指令的含义:

方法默认需要传入一个参数 int a, 所以局部变量表中index为0的位置为传入的5

局部变量表

index下标0
数值5

刚进入方法体,局部变量表第0个位置的数值为5,局部变量表的大小为1


操作数栈:

操作数栈为空

1. iconst_1

将常量1压入操作数栈

局部变量表:

index下标0
数值1

局部变量表无变化

操作数栈:

1

操作数栈 栈顶为1,操作数栈大小为1

2. istore 1

将操作数栈栈顶的1弹出,放入局部变量表1的位置

局部变量表:

index下标01
数值51

局部变量表第0个位置为5,第1个位置为1,局部变量表的大小为2

操作数栈:
由于操作数栈弹出了栈顶的1,此时操作数栈为空

3. iload 1

将局部变量表中index为1的元素1压入操作数栈

局部变量表:

index下标01
数值51

局部变量表无变化

操作数栈:

1

1被压入操作数栈,栈顶为1, 操作数栈大小为1

4. iload 0

将局部变量表中index为0的元素5压入操作数栈

局部变量表:

index下标01
数值51

局部变量表无变化

操作数栈:

5
1

5被压入操作数栈,栈顶为5, 操作数栈大小为2

5. iadd

弹出操作数栈栈顶两个元素,进行相加,并将相加的结果6再次压入操作数栈
局部变量表:

index下标01
数值51

局部变量表无变化

操作数栈:

6
6. istore 2

将操作数栈栈顶的6弹出,放入局部变量表2的位置

局部变量表:

index下标012
数值516

此时局部变量表的大小为3

操作数栈:
由于操作数栈弹出了栈顶的6,此时操作数栈为空

7. return

尽管这个方法是void,但是jvm虚拟机规范要求也要有return,如果返回int类型,则为 ireturn
局部变量表的最大size为3
操作数栈的最大size为2

三. 总结

至此,本篇主要讲了局部变量表和操作数栈在字节码中是如何操作,以及介绍了常见的几个操作指令。

  • iconst_1 将常数1压入到操作数栈
  • istore 弹出操作数栈顶的元素,放入到局部变量表对一个的下标位置
  • iload 取出局部变量表对应下标位置的元素,压入操作数栈的栈顶
  • iadd 弹出操作数栈顶的两个元素,进行相加,再将结果重新压入栈顶

JVM执行字节码,大多数是本地变量表,操作数栈,操作指令之间的协作,这也是理解字节码的关键所在。

本篇是基础,下一篇将详细讲解jvm操作符,如果对本章字节码操作指令不懂的,可以结合下一篇内容反复理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小强冲冲冲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值