首页 文章 精选 留言 我的

精选列表

搜索[android jetpack],共10000篇文章
优秀的个人博客,低调大师

Android MethodHandle 反射性能优化

一、关于指令调用 无论是基于栈的JVM还是还是基于寄存器的DVM,他们除了操作数栈中变量的移动和空间分配、以及程序计数器的不同,基本方法调用的基本指令都是遵守JSR规范的。 在讨论MethodHandle之前,说一下Java动态性缺陷。Java语言是一门偏向静态的语言,他的动态性一致存在很多局限: 泛型缺陷: 前端编译(javac)时泛型被擦除、泛型无法传递、泛型不支持值类型、不支持动态泛型 不支持动态方法替换 不支持普通类的动态代理 生成字节码的工具API相对繁琐等 反射调用校验太多活着需要生成大量字节码 MethodHandle主要解决的是问题: 【1】反射优化,MethodHandle属于轻量级直接调用字节码,而反射属于重量级,并且完全无法代替反射 【2】动态方法分派,能做到子类调用父类的方法,即便这个方法被子类复写了。 【3】调用运行在JVM上的其他语言 我们知道,在JSR标准中,提供了四种调用方法的指令 invokestatic : 调用静态方法(JIT 会对这种指令进行内联优化,而且不需要守护内联) invokevirtual :调用虚方法,一般指非私有方法 和final方法(JIT会通过类层次结构分析 (CHA),将此类方法去虚化,进一步实现内联,这种内联一般需要解释器守护,防止陷阱出现无法逃逸) invokespecial: 调用构造方法和非虚方法 (JIT 会对这种指令进行内联优化,而且不需要守护内联) invokeinterface: 调用接口方法(JIT是否优化不取决于这种调用,而是他的实现invokevirtual) MethodHandle本质上是为了调用JVM上其他语言,实际上也有方法分派的能力(注意:只能分派直接父类,JSR版本修改之前可以任意分派) public class MethodHandleDynamicInvoke { public static void main(String[] args) { Son son = new Son(); son.love(Father.class); son.love(Son.class); } } class Father { String thinking() { return "Father"; } } class Son extends Father { @Override String thinking() { return "Son"; } public void love(Class target) { MethodType methodType = MethodType.methodType(String.class); try { MethodHandle thinkingMethodHanle = MethodHandles.lookup().findSpecial(target, "thinking", methodType, Son.class).bindTo(Son.this); System.out.println("I love " + ((String) thinkingMethodHanle.invokeExact())); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (Throwable throwable) { throwable.printStackTrace(); } } } 输出结果如下 I love Father I love Son 二、MethodHandle如何优化反射? 前一节我们我们加单了解了JVM相关指令和MethodHandle解决的问题,接下来我们介绍以下几个重要的API MethodHandles.lookup() ; 方法查询器 MethodType.methodType(....); 用于返回值,参数匹配,动态参数,第一个参数是返回值类型,从第二个参数起是方法参数 MethodHandle.bindTo(Object obj) ;绑定执行对象,绑定之后,invoke活着invokeExact第一个参数就不能传当前对象了 MethodHanle.invoke(...) ; 该方法属于模糊参数类型,参数可以传入父类类型,当然成本是该方法执行效率相当低 MethodHandle.invokeExact(...) ;参数类型方法必须和调用的方法完全一致,如果是String必须转为String,不能用Object 代替,必要时进行类型转换,带来的收益是该方法执行效率高 Lookup findConstructor 、findSpecial 、findVirtual 、findStatic 、findXXXGetter、findXXXSetter ...用于方法查询,其中findSpecial查询非虚方法、findStatic查询静态方法 Lookup unreflectXXX 配合反射使用,因为MethodHandle并不能完全代替反射,比如调用不同包和class中的私有方法,需要通过反射,然后转为MethodHandle MethodHandle 如何做到性能优化的? MethodHandle静态化 提前bindTo性能会更高 调用invokeExact 下面我们给出一个例子,定义一个私有方法,提升反射性能 public class ClassMethodHandle { private int getDoubleVal(int val) { return val * 2; } } 测试代码如下 public class MethodHandleTest { static Method method_getDoubleVal; static MethodHandle methodHandle_getDoubleVal; static { try { MethodHandles.Lookup lookup = MethodHandles.lookup(); method_getDoubleVal = ClassMethodHandle.class.getDeclaredMethod("getDoubleVal",int.class); method_getDoubleVal.setAccessible(true); methodHandle_getDoubleVal = lookup.unreflect(method_getDoubleVal); //私有方法不能通过findSpecial访问,需要借助Method Reflection } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } public static void main(String[] args) throws Throwable { long startTime = System.nanoTime(); testMethodReflection(); long dx1 = System.nanoTime() - startTime; System.out.println("[1] " + (dx1)); startTime = System.nanoTime(); testMethodHandle(); long dx2 = System.nanoTime() - startTime; System.out.println("[2] " + (dx2)); System.out.println(">>"+(dx1*1f)/dx2+"<<"); } private static void testMethodReflection() { try { List<Integer> dataList = Arrays.asList(1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); for (int i=0;i<5;i++) { MethodHandleTest.transformRelection(dataList,method_getDoubleVal,new ClassMethodHandle()); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Throwable throwable) { throwable.printStackTrace(); } } private static void testMethodHandle() throws Throwable { List<Integer> dataList = Arrays.asList(1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); for (int i=0;i<5;i++) { MethodHandleTest.transform(dataList, methodHandle_getDoubleVal, new ClassMethodHandle());// 方法做为参数 } } public static List<Integer> transformRelection(List<Integer> dataList, Method method,Object obj) throws Throwable { for (int i = 0; i < dataList.size(); i++) { dataList.set(i, (int) method.invoke(obj,dataList.get(i)));//relect invoke } return dataList; } public static List<Integer> transform(List<Integer> dataList, MethodHandle handle,Object obj) throws Throwable { for (int i = 0; i < dataList.size(); i++) { dataList.set(i, (int) handle.invokeExact((ClassMethodHandle)obj,(int)dataList.get(i)));//注意参数类型转换 } return dataList; } } 性能测试结果如下,取5次中的最大值 [1] 2952626 [2] 1031642 >>2.8620646<< 如果提前绑定呢? public class MethodHandleTest { static Method method_getDoubleVal; static MethodHandle methodHandle_getDoubleVal; static { try { MethodHandles.Lookup lookup = MethodHandles.lookup(); method_getDoubleVal = ClassMethodHandle.class.getDeclaredMethod("getDoubleVal", int.class); method_getDoubleVal.setAccessible(true); methodHandle_getDoubleVal = lookup.unreflect(method_getDoubleVal).bindTo(new ClassMethodHandle()); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } public static void main(String[] args) throws Throwable { long startTime = System.nanoTime(); testMethodReflection(); long dx1 = System.nanoTime() - startTime; System.out.println("[1] " + (dx1)); startTime = System.nanoTime(); testMethodHandle(); long dx2 = System.nanoTime() - startTime; System.out.println("[2] " + (dx2)); System.out.println(" "+((dx1*1f)/dx2)); } private static void testMethodReflection() { try { ClassMethodHandle classMethodHandle = new ClassMethodHandle(); List<Integer> dataList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); for (int i = 0; i < 5; i++) { MethodHandleTest.transformRelection(dataList, method_getDoubleVal, classMethodHandle); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Throwable throwable) { throwable.printStackTrace(); } } private static void testMethodHandle() throws Throwable { List<Integer> dataList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); for (int i = 0; i < 5; i++) { MethodHandleTest.transform(dataList, methodHandle_getDoubleVal);// 方法做为参数 } } public static List<Integer> transformRelection(List<Integer> dataList, Method method, Object obj) throws Throwable { for (int i = 0; i < dataList.size(); i++) { dataList.set(i, (int) method.invoke(obj, dataList.get(i)));//relect invoke } return dataList; } public static List<Integer> transform(List<Integer> dataList, MethodHandle handle) throws Throwable { for (int i = 0; i < dataList.size(); i++) { dataList.set(i, (int) handle.invokeExact((int) dataList.get(i)));//注意参数类型转换 } return dataList; } } 性能测试,取5次中的最大值 [1] 5893674 [2] 1279878 4.6048717

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册