下图是一亿次循环的耗时:
反射的速度差异只在大量连续使用才能明显看出来,理论上100万次才会说反射很慢,对于一个单进单出的请求来说,反射与否根本差不了多少。
事实上各大框架注解,甚至业务系统中都在使用反射,不能因为慢就不用了。
在后台Controller中序列化请求响应信息大量使用注解,高并发就意味着连续百万级别调用反射成为可能,各大MVC框架都会着手解决这个问题,优化反射。
反射核心的是getMethod和invoke了,分析下两者的耗时差距,在一亿次循环下的耗时。
证明getMethod很耗时,所以说我们要优先优化getMethod,看看为什么卡?
getMethod最后直接调用native方法,无解了。想复写优化getMethod是不可能的了,官方没毛病。
但是我们可以不需要每次都getMethod啊,我们可以缓存到redis,或者放到Spring容器中,就不需要每次都拿了。
我们看下invoke的源码:
尴尬,最后还是native方法,依然没毛病。
invoke不像getMethod可以缓存起来重复用,没法优化。
所以这里需要引入ASM,并做了个工具库reflectAsm:
参考: https://blog.csdn.net/zhuoxiuwu/article/details/78619645 , https://github.com/EsotericSoftware/reflectasm
使用如下:
参考: https://blog.csdn.net/z69183787/article/details/51657771
invoke是没办法优化的,也没办法做到像直接调用那么快。所以大佬们脑洞大开,不用反射的invoke了。原理如下:
实际上reflectAsm是有个致命漏洞的,因为要生成文件,还得load进JVM,所以reflectAsm的getMethod特别慢:
虽然getMethod很慢,但是invoke的速度是到达了直接调用的速度了。
下面是反射优化的测试样例:
java反射需要将内存中的对象进行解析,涉及到与底层c语言的交互,速度会比较慢。java反射得到的每一个Method都有一个root,不暴漏给外部,而是每次copy一个Method。具体的反射调用逻辑是委托给MethodAccessor的,而accessor对象会在第一次invoke的时候才创建,是一种lazy init方式。而且默认Class类会cache method对象。目前MethodAccessor的实现有两种,通过设置inflation,一个native方式,一种生成java bytecode方式。native方式启动快,但运行时间长了不如java方式,个人感觉应该是java方式运行长了,jit compiler可以进行优化。所以JDK6的实现,在native方式中,有一个计数器,当调用次数达到阀值,就会转为使用java方式。默认值是15。java方式的实现,基本和非反射方式相同。
您好:反射的性能远远低于直接调用,但对于必须要使用的场景,它的性能并非不可接受。对于“反射肯定是造成性能差的主要原因”这种说法,要冷静客观的分析。
.NET平台可以使用元数据完整的描述类型(类,结构,委托,枚举,接口)。许多.NET技术,例如WCF或序列化都需要在运行时发现类型格式。在.NET中,查看和操作元数据的动作称为反射(也称为元编程)。
欢迎分享,转载请注明来源:优选云