博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
对《基于动态代码生成技术的动态对象工厂》一文的补充
阅读量:4123 次
发布时间:2019-05-25

本文共 1838 字,大约阅读时间需要 6 分钟。

 
写完《 》一文后我一直很奇怪为什么动态代码生成的方法相对于直接使用new有如此大的劣势?道理上说动态代码一旦生成,那么它和原生代码应该也没什么区别了,那么它的执行效率应该和相应的原生代码差别不大才对。仔细观察Creator.New版本的执行过程,我猜测问题并不是出在动态生成的代码本身,而是出在周围的代码上。在我的测试程序中,我对以下代码返复调用1000万次:
A a 
=
 (A)Creator.New(
typeof
(A), 
"
a
"
);
而Createor.New方法中要对一个SortedList进行查找,找到满足条件的Creator子类实例,然后调用它的CreateObject方法来产生对象,此查找的过程可能会很影响效率,为此我把测试部分的代码改为如下:
 
           
object
[] param 
=
 
new
 
object
[] 
"a" }
;
            Creator creator 
=
 Creator.GetCreator(
typeof
(A), param);
            DateTime dt3 
=
 DateTime.Now;
            
for
 (
int
 i 
=
 
0
; i 
<
 count; i
++
)
            
{
                A a 
= (A)creator.CreateObject(param);
            }
            DateTime dt4 
=
 DateTime.Now;
显然这样做给了动态代码生成方式很大的优待,我首先取得了合适的creator子类对象,并且已经把要传的参数数组准备好了,循环里面所做的只是单纯调用动态生成的代码。不过这没关系,我就是要看看在极优环境下动态生成的代码的执行效率如何,相比直接使用new会差多少。相应的,对直接使用new方法的测试代码如下:
            DateTime dt4 
=
 DateTime.Now;
            
for
 (
int
 i 
=
 
0
; i 
<
 count; i
++
)
            
{
                A a 
= new A("a");
            }
            DateTime dt5 
=
 DateTime.Now
为了减少影响,这里的循环上限count都被声明为const,在编译的结果中会以其值直接替代。这里为了减少误差,把循环次数增加到一亿次。此外我还把所有的构造函数的方法体都改成空的,以减少这些操作需要的时间。这样测得的结果如下:
优化后重复一亿次所需时间(毫秒)
调用方式
Creator.CreateObject
直接使用new
引用类型参数
1个参数
2312.5
1093.75
3个参数
2593.75
1109.375
9个参数
2687.5
1093.75
值类型参数
1个参数
1937.5
1078.125
3个参数
3000
1093.75
9个参数
5343.75
1093.75
下面是关于此结果的几点分析:
1 此次测试结果明显好于上一次,动态生成的代码运行时间只是直接使用new的2-4倍。可见前面所做的分析是正确的,执行动态代码本身和执行原生代码在效率上没有什么差别。
2 之所以仍有2-4倍的差别,我觉得是因为动态生成的代码在参数进栈时需要先从数组中取得参数才能进栈,这样显然比直接使用new时用ldstr或类似指令要慢一些,2-4倍的差别比较正常
3 参数为引用类型动态代码的时间只是new的2倍多,而参数为值类型时倍数则较多,这是因为参数为引用类型时在从数组中取值之后需要一个拆箱操作,显然此操作是非常慢的。
4 调用动态代码时参数个数不同时所需时间也会增加,这个和预想的一样,因为由动态生成代码的部分可以看出,参数越多for循环执行的次数也越多,生成的IL代码就越长。
5 代码执行时间并不随参数的个数成倍数关系增长,这里大概因为从数组中取值的速度比较快,而newobj指令是最慢的,因此参数个数的影响不是很大。但参数为值类型时,时间增长的较快,这更说明了拆箱操作是很慢的,对结果的影响较大
6 参数为一个值类型时比参数为一个引用类型时动态代码所用的时间更短(值类型时为1937.5),引用类型时为(2312.5),但直观想象的话应该是引用类型的快一些才对,因为它不需要拆箱,并且拆箱也是个慢操作,但这与测试结果不符,我还不太清楚这是为什么。
7因同一段代码返复测试时时间也会有一些浮动,因此可以认为各种不同参数时new方法的时间几乎没有差别,可见像ldstr、ldc.i4这样的压栈操作速度是非常快的,相对于newobj来说几乎可以忽略不计。
 

转载地址:http://vcopi.baihongyu.com/

你可能感兴趣的文章
面试时会问到的项目中的问题总汇
查看>>
Netty有什么用?
查看>>
HashMap为什么2倍扩容
查看>>
详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
查看>>
解决docker 启动 centos 镜像,容器会自动退出问题
查看>>
ftp文件出现乱码
查看>>
ES安装启动及could not find java in bundled jdk at /opt/elasticsearch/elasticsearch-7.9.1/jdk/bin/java报错
查看>>
什么是脑裂?Zookeeper怎么解决脑裂问题的?
查看>>
redis加锁的几种方法
查看>>
什么是RPC?RPC与Stub简述
查看>>
什么是EJB?EJB详解
查看>>
java进程间通信的几种方式? 对比总结
查看>>
报错org.thymeleaf.exceptions.TemplateInputException: Error resolving template解决方案
查看>>
启动项目报错:org.apache.catalina.LifecycleException: Failed to start component
查看>>
BindingResult是什么?BindingResult的使用方法详解
查看>>
linux关闭防火墙了,但端口还是访问不了/虚拟机能ping通,但是telnet某个端口却不行
查看>>
StringBuffer的扩容机制为什么是两倍的原数组长度 + 2
查看>>
Java的double和float类型计算丢失精度问题,bigdecimal用法
查看>>
./configure make && make install 是什么意思
查看>>
springioc的好处
查看>>