IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> AviatorScript编译生成的字节码为何比Java代码慢? -> 正文阅读

[Java知识库]AviatorScript编译生成的字节码为何比Java代码慢?

一、快速了解

1.问题
实现同样功能的Java代码与AviatorScript代码,两者均会将代码编译成JVM可以执行的字节码,但是两者执行代码所消耗的时间,却有几十倍甚至上百倍的差距。在AS(AviatorScript简称)中,实现相同的功能,更换一种写法,其执行耗时可能也存在极大的差距。
2.原因
? AS将表达式编译生成的字节码与Java代码编译生成的字节码有较大差异,AS生成的字节码在执行时存在大量的类型转换、条件判断以及为了统一输入输出所做的额外操作,这些都是AS生成的字节码执行速度慢的原因,并且一个表达式并非只生成一个字节码,例如一个单纯的 if-else 逻辑的表达式,AS会生成四份字节码,而执行时使用的是最后一份,其会引用前三份字节码。此处为其性能比不上Java生成的字节码的核心原因。
? AS编译表达式生成的字节码其继承了 ClassExpression 类并重写了 public abstract Object execute0(Env env)方法,AS最终是通过执行 execute0(env) 方法获取表达式的结果,但AS提供给用户获取表达式执行结果的方法是 execute() ,对 execute0() 方法做了包装,其主要作用是:将用户传入的HashMap转换成Env并对Env内部的一些参数进行配置;添加了执行 execute0() 方法时的异常捕获等方法。此处虽然进行了前期执行的准备工作,但并非其性能问题的核心点;
? 经过测试:1千万次执行,执行execute()方法会比执行execute0()方法多耗时150ms;

二、AS字节码反编译结果

获取AS动态生成的字节码方式:AS获取动态生成的字节码

1.字节码反编译结果举例

1.1 if-else获取两个数的最大值:
表达式:

if (num1 > num2) {
    return num1;
} else {
    return num2;
}

动态生成字节码反编译结果:

public class Script_1633877984542_59 extends ClassExpression {
    private final AviatorJavaType f0;
    private final AviatorFunction f1;
    public Script_1633877984542_59(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {
        super(var1, var2, var3);
        this.f0 = new AviatorJavaType("num1", var3);
        this.f1 = var1.getFunction("__reducer_return", var3);
    }
    public final Object execute0(Env var1) {
        return RuntimeUtils.assertNotNull(this.f1.call(var1, this.f0)).deref(var1);
    }
}
public class Script_1633878073270_60 extends ClassExpression {
    private final AviatorJavaType f0;
    private final AviatorFunction f1;
    public Script_1633878073270_60(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {
        super(var1, var2, var3);
        this.f0 = new AviatorJavaType("num2", var3);
        this.f1 = var1.getFunction("__reducer_return", var3);
    }
    public final Object execute0(Env var1) {
        return RuntimeUtils.assertNotNull(this.f1.call(var1, this.f0)).deref(var1);
    }
}
public class Script_1633878131216_61 extends ClassExpression {
    private final AviatorJavaType f0;
    public Script_1633878131216_61(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {
        super(var1, var2, var3);
        this.f0 = new AviatorJavaType("__reducer_empty", var3);
    }
    public final Object execute0(Env var1) {
        return this.f0.deref(var1);
    }
}
public class Script_1633877984542_58 extends ClassExpression {
    private final AviatorJavaType f0;
    private final AviatorJavaType f1;
    private final AviatorFunction f2;
    public Script_1633877984542_58(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {
        super(var1, var2, var3);
        this.f0 = new AviatorJavaType("num1", var3);
        this.f1 = new AviatorJavaType("num2", var3);
        this.f2 = var1.getFunction("__if_callcc", var3);
    }
    public final Object execute0(Env var1) {
        return RuntimeUtils.assertNotNull(this.f2.call(var1, (this.f0.compare(this.f1, var1) > 0 ? AviatorBoolean.TRUE : AviatorBoolean.FALSE).booleanValue(var1) ? RuntimeUtils.assertNotNull(RuntimeUtils.getFunction(this.newLambda(var1, "Lambda_1633877984542_57"), var1).call(var1)) : RuntimeUtils.assertNotNull(RuntimeUtils.getFunction(this.newLambda(var1, "Lambda_1633878073270_58"), var1).call(var1)), this.newLambda(var1, "Lambda_1633878131216_59"))).getValue(var1);
    }
}

1.2 Math函数获取两个数的最大值
表达式:

return Math.max(num1, num2);

动态生成字节码反编译结果:

public class subClassExpression extends ClassExpression {
    private final AviatorJavaType f0;
    private final AviatorJavaType f1;
    private final AviatorFunction f2;
    public subClassExpression(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {
        super(var1, var2, var3);
        this.f0 = new AviatorJavaType("num1", var3);
        this.f1 = new AviatorJavaType("num2", var3);
        this.f2 = var1.getFunction("Math.max", var3);
    }
    public final Object execute0(Env var1) {
        return RuntimeUtils.assertNotNull(this.f2.call(var1, this.f0, this.f1)).getValue(var1);
    }
}

1.3 三元运算获取两个数最大值
表达式:

return num1 > num2 ? num1 : num2;

动态生成字节码反编译结果:

public class subClassExpression extends ClassExpression {
    private final AviatorJavaType f0;
    private final AviatorJavaType f1;
    public subClassExpression(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {
        super(var1, var2, var3);
        this.f0 = new AviatorJavaType("num1", var3);
        this.f1 = new AviatorJavaType("num2", var3);
    }
    public final Object execute0(Env env) {
        return ((this.f0.compare(this.f1, env) > 0 ? AviatorBoolean.TRUE : AviatorBoolean.FALSE).booleanValue(env) ? this.f0 : this.f1).getValue(env);
    }
}

2. 分析

根据上述例子可以知道,求两个数的最大值,不同的写法,经过AS转换后生成的字节码反编译后的结果也完全不一样,而不一样的字节码其执行耗时也不一样,在不修改源码的基础上,想要AS执行速度快,就得在表达式的编写上下功夫,让其生成最优的字节码。
因为AS编译生成的字节码的变量类型是Aviator自己定义的,里面封装了许多方法,方法参数类型几乎都是AviatorObject类型,相当于Java的Object类,而AviatorObject类一般不参与计算,最终需要转换成基本类型进行计算,所以每次调用方法进行运算,基本上都伴随着类型校验、类型转换,直到AS认为该类型符合自己的要求后,才开始进行计算。
类型转换大致流程: AviatorJavaType (初始类型)-> AviatorObject (经过方法变为父类类型)-> AviatorJavaType (方法内转换成具体实现类)-> Object (通过env获取的类型)-> AviatorNumber (判断Object类型并转换)-> AviatorObject (调用方法变成父类)-> AviatorNumber (判断为这个类型后强转)->判断其具体为 AviatorType.Long 、 AviatorType.Double 等,获取其对应类型的值,进行计算。为了对两个数字类型的值进行比较大小,其进行了最少7次以上的类型校验以及转换,这些都是因为AviatorScript身为一个弱类型的语言,参数的具体类型只有在计算的时候从env中获取并判断后才知道具体类型,同时为了保证方法的通用型,其可以接收一个通用类型,然后方法内进行判断具体类型应该走什么逻辑分支,而这也导致类型转换变成一个耗费性能点。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-25 12:24:25  更:2021-10-25 12:25:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:02:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码