在本系列的
第一篇文章中,我们介绍了Java的强类型及动态类型系统 。结论就是这个类型系统让你可以写出表述性强,健壮的应用程序,但是它限制了框架API与用户类型协作的能力。我们还知道了为什么Java的反射API并不总是与用户类型交互的最佳方式。为了将这点解释清楚,我们还分析了一个简单的安全库的实现,它使用了反射API,但却破坏了类型安全,为了保留用户类型,我们使用了代码生成的方式。
在文章的第二部分,我们分析了不同的代码生成库,并重点介绍了一下我自己开发的一个库,
Byte Buddy。然后我们基于这个库来实现了一个简单的安全框架。
本文是最后一篇,我们想比较一下不同的库实现之间的性能差别。如果你还没读过前面两部分,最好先看一遍再继续阅读本文。我保证,我会等你看完再继续往下讲(注:这是哄小孩子吗:-))
初识代码生成器
总的来说,好的API并不是一个优秀的代码生成库的唯一条件。代码库的运行时性能可能是一个更重要的因素,尤其是当生成的代码在运行的程序中处于一个比较关键的位置的时候。关于代码生成库的性能,坊间有着诸多传闻,不过我还没找到关于任何一项技术的靠谱的基准测试。
在Java中进行微基准测试并不是一件容易的事情 。如果你要测量一个指定的代码块的执行时间,你通常不知道你测量的到底是什么。Java代码在执行的时候,JIT编译器通常都会介入,最极端的情况下,它可能会擦除掉被测量的代码。
然而在过去的几年里,有几个聪明的家伙想出了一些办法来欺骗JIT编译器,并基于这些想法实现了一些微基准测试的库。我个人最喜欢的是
Java Microbenchmarking Harness,它是随着Open JDK发布的一款工具。
在进行数据测量之前,有必要先回答一个问题:基准测试的目标和关注点是什么?很明显,有些任务使用某个库处理起来可能会更高效些,而另一些任务则可能花的时间就要更长一点。
除此之外,代码生成库通常会牺牲创建类的时间来减少生成类的方法调用的时间。当我们在讨论下面这些数据的时候,应当时刻牢记这点。
看下这些数据吧
在记住我们前面说的东西的同时,我们先来看一个直接比较不同任务的运行时间的JMH基准测试的原始数据。下表中的数据是指每个操作所需要的纳秒数,空格中是采样的标准误差。
|
Byte Buddy | | cglib | | javassist | | JDK proxy |
使用stub方法实现接口 | 153.800 | (0.394) | 804.000 | (1.899) | 706.878 | (4.929) | 973.650 | (1.624) |
调用子方法 | 0.001 | (0.000) | 0.002 | (0.000) | 0.009 | (0.000) | 0.005 | (0.000) |
继承类调用父类方法 | 172.126 | (0.533) | 1480.525 | (2.911) | 625.778 | (1.954) | - | |
| 2290.246 | (7.034) | | | | | | |
调用父类方法 | 0.002 | (0.000) | 0.019 | (0.000) | 0.027 | (0.000) | - | |
| 0.003 | (0.000) | | | | | | |
第一行显示的是库生成这18个不同接口的空实现所需的时间。在这些生成的运行时类的基础之上,第二行显示的是调用这个生成类实例中的方法所需要的时间。
在这次测试中,Byte Buddy以及cglib的性能最好,因为这两个库你都能将返回值硬编码到生成类中,而javassist和JDK代理都只允许注册一个相应的回调函数。
这样我们可以得出第一个粗略的结论,这就是运行时类的方法实现越具体的话性能越好。听起来显然应该是这样,但其实不然,因为JIT编译器可能会优化这两种方法的性能。
类继承的情况如何
上表中的第三行显示的是继承一个包含18个方法的类所需要的时间。这次并不是创建一个方法存根,而是重写了方法,并调用了它父类的实现。
你可能已经注意到了,Byte Buddy列出了两个测量值,而第二个斜体的数字明显要更大。两个数值代表的是实现父方法调用的两种不同的实现方式。
正如上周所提到的,JVM只允许在同一个实例内进行父方法的调用。因此,调用super方法的最简单的方式就是在拦截方法里进行父方法的调用,这个拦截方法在第一次测试的时候已经实现好了。
但这个方法的灵活性不够,比方说它并不能根据条件来进行调用。为了克服这一限制,Byte Buddy允许你创建一个类似内部类的东西。在本文的前一部分中我们就介绍过了这种方法,在那篇文章中我们生成了一个实现了Callable接口的代理类。
对于任何调用而言,内部类的实例是通过方法中的一个参数所对应的注解注入到拦截方法里的。正如你所看到的,这种创建了一个额外的类的方式,跟其它使用相同策略的库相比,调用super方法所消耗的时间大大减少了。
与此同时,为每个方法生成一个专门的类会带来生成子类的额外开销。cglib和javassist都选择了一种折中的方案来解决这一问题,它们省掉了创建额外类的开销,代价就是每次父方法调用都会增加额外的开销。
结束语:都是为了提升性能
这里有许多值得讨论的东西,不过与此同时,这也是个结束这次代码生成简介的重要时刻。我希望这次概述能帮助你认识到代码生成其实并没有什么神秘的,这并不是只有大型框架才能使用的。有一个顺手的库的话,即使是很小的项目,你也可以使用代码生成来完成切面关注的漂亮的API,而不用增加显式的依赖关系。
现在Java 8已经开始逐渐流行起来,它的新的元空间不再严格限制Java应用包含的类的数量了。有了这些之后,就没有什么能再束缚住你的手脚了,放手去干吧。
原创文章转载请注明出处:
http://it.deepinmind.com
英文原文链接
分享到:
相关推荐
4. **代码生成算法**:垃圾代码生成器的核心是其算法,它可能通过随机字符串生成、语法结构模拟等方式产生代码。理解这些算法可以帮助开发者了解如何生成不同类型的代码片段。 5. **测试与调试**:在iOS项目中使用...
4. **ORM支持**:高级的代码生成工具可能支持ORM(对象关系映射)框架,如Entity Framework或NHibernate,直接生成符合ORM规则的代码,简化数据库操作。 5. **扩展性**:工具可能提供扩展点,允许用户添加自定义的...
7. 工具使用:对于名为"ZCJTemplateTool-master 2"的压缩包文件,它可能是一个特定的代码生成工具的源码仓库。使用前,开发者需要了解其工作原理和使用方法,遵循相关文档进行配置和集成。 总的来说,【iOS垃圾代码...
4. **代码模板定制**:为了满足不同开发团队的编码规范,一些高级的实体代码生成器允许用户自定义代码模板。这样,生成的代码可以按照团队的约定,比如命名规则、注释风格等。 5. **性能优化**:通过使用实体代码...
【标题解析】 标题"mybatis-plus 达梦 代码生成...综上所述,这个资源提供了一个使用Mybatis-Plus与达梦数据库集成的代码生成解决方案,包括了完整的配置和必要的依赖,为基于达梦数据库的Java项目开发带来了便利。
4. **跨平台**:Python可以在多个操作系统上运行,这意味着生成的C++代码生成器也可应用于多种环境。 【Python实现C++代码生成器】 使用Python编写C++代码生成器通常包括以下几个步骤: 1. **定义模板**:定义C++...
STM8函数库代码生成器是一款专为STM8微控制器设计的工具,用于帮助开发者便捷地查询和生成STM8库函数的代码。STM8是意法半导体(STMicroelectronics)推出的一种8位微控制器系列,广泛应用于各种嵌入式系统设计中。...
代码生成技术涉及的语言可以包括但不限于Java、Python、C++、Go等,每种语言都有其特定的代码生成库或工具,例如Java中的FreeMarker和JOOQ,Python的cookiecutter等。 【压缩包子文件的文件名称列表】中的"CALL转换...
动态代码生成通常涉及以下几个核心概念和技术: 1. **元编程**:元编程允许程序员在编译时或运行时编写或修改程序自身。动态代码生成就是元编程的一种体现,通过自动生成代码,可以灵活地调整程序的行为,以适应...
【标签】:“代码生成器”标签明确了这个压缩包的主要内容,即与代码生成相关的工具或代码库。这类工具通常用于快速构建应用的基础架构,适用于iOS开发、Web开发、后端开发等多个领域。 【压缩包子文件的文件名称...
总的来说,STM32代码生成器是一个强大的辅助工具,它可以简化STM32开发流程,提高开发效率,使开发者能够快速地实现功能并专注于更高级别的应用逻辑。结合库文件和使用说明,开发者可以充分利用这个工具,实现高效、...
4. **代码生成的应用场景**:视频可能讨论了几个常见的手工代码生成应用场景,如动态SQL生成(用于ORM框架如Hibernate或Entity Framework)、元编程、性能优化(如减少不必要的中间对象创建)以及自定义编译时或运行...
在Go中,有许多库和工具支持代码生成,如`go generate`命令,它可以读取源代码中的特殊注释,执行自定义的生成任务。 3. **数据库反向工程**:数据库反向工程是将已存在的数据库结构转换为源代码的过程。在这个项目...
4. **代码优化**:生成的代码经过优化,尽可能减少了冗余和不必要的操作,提高代码执行效率。 5. **版本管理**:支持不同版本的STM32Cube库,确保生成的代码与库版本兼容,适应不断更新的固件库。 6. **移植性**:...
它可能集成了最新的编程范式、库和框架,以确保代码生成器能够跟上.NET技术发展的步伐。 在实际项目开发中,合理地应用“动软代码生成器”这一类辅助工具,对于提高团队的工作效率和降低项目开发成本至关重要。通过...
4. `Enyim.Caching.dll` 和 `HY.Caching.dll`:这些可能是缓存管理库,如EnyimMemcached或自定义的缓存实现,用于提高代码生成过程的性能,减少不必要的数据库查询。 5. `MySql.Data.dll`:这是MySQL官方的.NET数据...
Simulink是MATLAB环境下的一个模块化建模工具,常用于系统仿真、控制系统设计以及自动代码生成。这个“Simulink代码生成自动化.zip”文件显然包含了一个自动化流程,能够帮助用户简化Simulink模型到实际代码的转换...
STM8S代码生成器是一款专为STM8系列微控制器(MCU)设计的实用工具,主要功能是自动生成适用于STM8S芯片的C语言代码。STM8S是意法半导体(STMicroelectronics)推出的一款8位微控制器,广泛应用在各种嵌入式系统中,...
本篇文章主要探讨的是四个流行的C++ JSON库:SimpleJSON, jsoncpp, libjson, 和 rapidjson,在VS2010环境下的性能对比。 首先,让我们逐一了解这些库: 1. **SimpleJSON**:这是一个开源、轻量级的库,提供简单的...