`
izuoyan
  • 浏览: 9221996 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

从Java汇编来看Java程序的性能优化

阅读更多

<!-- [if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:PunctuationKerning/> <w:DrawingGridVerticalSpacing>7.8 pt</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:Compatibility> <w:SpaceForUL/> <w:BalanceSingleByteDoubleByteWidth/> <w:DoNotLeaveBackslashAlone/> <w:ULTrailSpace/> <w:DoNotExpandShiftReturn/> <w:AdjustLineHeightInTable/> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:UseFELayout/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!-- [if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]--><!-- [if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]-->

原文作者为我们指出了一条提高Java 性能的有效方法:使用Java 汇编,但是如何权衡效率与其他软件性能(如可维护性、扩展性)等等,需要读者根据项目需要做出取舍。

这些天一直在用Oolong 学习Java 汇编, 也试图反编译一些java 代码。在这之间突然意识到原来自己过去犯了很多编程的误区,导致代码效率低下。这里列出一些需要注意的地方


1. 尽量避免使用iterator (不是必要的话)

原来自己看C++ 的书,看到STL 里的iterator 的用法,很多书上说这种用法好,如果实现一变,iterator 的代码可以不用修改。我是一个很信书的人,自从那时候开始,我就喜欢上用iterator 了,比如以下代码(第一段)

for(int i=0;i<results.size();i++){
String result = results.get(i);
}

都换成了(第二段)

Iterator<String> iter = results.iterator();
while(iter.hasNext()){
String result = iter.next();
}

最近学习Oolong, 反编译这两段代码,妈妈啊

第一段的Java 汇编是

.line 11
l9: iconst_0
l10: istore 5
l12: iload 5
l14: aload 4
l16: invokevirtual java/util/ArrayList/size ()I
l19: if_icmpge l40
.line 12
l22: aload 4
l24: iload 5
l26: invokevirtual java/util/ArrayList/get (I)Ljava/lang/Object;
l29: checkcast java/lang/String
l32: astore 6
.line 11
l34: iinc 5 1
l37: goto l12
第二段的Java 汇编是

.line 15
l40: aload 4
l42: invokevirtual java/util/ArrayList/iterator ()Ljava/util/Iterator;
l45: astore 5
.line 16
l47: aload 5
l49: invokeinterface java/util/Iterator/hasNext ()Z 1
l54: ifeq l72
.line 17
l57: aload 5
l59: invokeinterface java/util/Iterator/next ()Ljava/lang/Object; 1
l64: checkcast java/lang/String
l67: astore 6
.line 18
l69: goto l47
仔细一看,前一段用的是invokevirtual ,后面那段用的是invokeinterface ,原理上来说invokeinterface 的速度比 invokevirtual 要慢得多,测试两段代码发现,后一段代码耗时比前一段多一个数量级,以后千万不要乱用iterator

二如果没有必要,尽量不要使用接口

原来写程序的时候,迷信类型分装,结果不分青红皂白,返回对象清一色的接口

比如一个返回中间结果的方法变成了这样:

public List<String> getList(){
List<String> results = new ArrayList<String>();

return results;
}

处理的方法象这样

public void handle(List<String> contents){
for(int index=0;index<contents.size();index++){
String content = contents.get(index);
}
}

反编译handle 发现

.line 9
l0: iconst_0
l1: istore_2
l2: iload_2
l3: aload_1
l4: invokeinterface java/util/List/size ()I 1
l9: if_icmpge l29
.line 10
l12: aload_1
l13: iload_2
l14: invokeinterface java/util/List/get (I)Ljava/lang/Object; 2
l19: checkcast java/lang/String
l22: astore_3
.line 9
l23: iinc 2 1
l26: goto l2
哎哟,又是invokeinterface ,赶紧的改回来

public void handle(ArrayList<String> contents){
for(int index=0;index<contents.size();index++){
String content = contents.get(index);
}
}

public ArrayList<String> getList(){
ArrayList<String> results = new ArrayList<String>();

return results;
}
这会好了,不在是invokeinterface ,是invokevirtual ,快啊

.line 9
l0: iconst_0
l1: istore_2
l2: iload_2
l3: aload_1
l4: invokevirtual java/util/ArrayList/size ()I
l7: if_icmpge l25
.line 10
l10: aload_1
l11: iload_2
l12: invokevirtual java/util/ArrayList/get (I)Ljava/lang/Object;
l15: checkcast java/lang/String
l18: astore_3
.line 9
l19: iinc 2 1
l22: goto l2
. 1.5 的新特性, 小心使用

看到1.5 的新特性,好用啊,这个

for(String content:contents){
}

反编译,怎么还是iterator?, 小心, 别乱用哦

l0: aload_1
l1: invokevirtual java/util/ArrayList/iterator ()Ljava/util/Iterator;
l4: astore_2
l5: aload_2
l6: invokeinterface java/util/Iterator/hasNext ()Z 1
l11: ifeq l27
l14: aload_2
l15: invokeinterface java/util/Iterator/next ()Ljava/lang/Object; 1
l20: checkcast java/lang/String
l23: astore_3
.line 10
l24: goto l5
.1.5 中的String 不再是可怕的性能瓶颈啦

effective java 里曾经说过,尽量少用String 做连接运算,做字符串连接运算时,StringBuffer 性能更好,可以减少new String 的次数

可是在1.5 里尝试以下代码

String contents = "";
for(int i=0;i<10000;i++)
contents += "Hello";

结果反编译一看,完全不是那么回事

.line 9
l0: ldc ""
l2: astore_1
.line 10
l3: iconst_0
l4: istore_2
l5: iload_2
l6: sipush 10000
l9: if_icmpge l38
.line 11
l12: new java/lang/StringBuilder
l15: dup
l16: invokespecial java/lang/StringBuilder/<init> ()V
l19: aload_1
l20: invokevirtual java/lang/StringBuilder/append (Ljava/lang/String;)Ljava/lang/StringBuilder;
l23: ldc "Hello"
l25: invokevirtual java/lang/StringBuilder/append (Ljava/lang/String;)Ljava/lang/StringBuilder;
l28: invokevirtual java/lang/StringBuilder/toString ()Ljava/lang/String;
l31: astore_1
.line 10
l32: iinc 2 1
l35: goto l5
这里用的就是StringBuffer 的替代品StringBuilder, 当然可能是IBMJava 编译器优化,或者是1.5 的编译器优化了(今后在证实),反正目前在ibm JRE1.5 上编译出来的String 连接代码完全是高效的,至少目前我能放心的用了

分享到:
评论

相关推荐

    java反汇编工具

    Java反汇编工具是用于查看和理解Java字节码的软件,它可以帮助开发者或安全研究人员深入洞察Java程序的内部工作原理。在Java平台中,源代码被编译成字节码,这是一种中间语言,可以在Java虚拟机(JVM)上运行。反...

    Java语言程序设计.pdf

    从提供的文件信息来看,该文件名为《Java语言程序设计.pdf》,主要涉及Java语言程序设计的相关知识。以下是从文件【部分内容】中提取并解释的知识点: 1. Java语言程序设计的基本概念:Java是一种面向对象的编程...

    一牛人用汇编写的雷电程序

    从部分代码来看,这些十六进制数字代表了汇编指令的机器码,是汇编语言程序在被编译后直接运行的形式。每一组数字对应着特定的处理器指令,如数据加载、存储、算术运算、逻辑操作、跳转等。通过分析这些机器码,可以...

    十分牛的汇编程序 谁看谁知道

    汇编程序通常用于编写操作系统内核、设备驱动程序、实时系统以及优化性能关键的部分。 在【压缩包子文件的文件名称列表】中,“国际编程大赛及DEMO作品欣赏”表明这个压缩包可能包含了一些在国际编程比赛中展示的...

    java_JMF的配置汇编.pdf

    从提供的部分内容来看,我们可以提取以下知识点: 1. JMF版本:文中提到了JMF2.1,这是JMF较早的版本之一。需要注意的是,随着Java技术的发展,JMF已经不再被Sun(现Oracle)官方支持,开发者可能会转向更现代的...

    JAVA上百实例源码以及开源项目源代码

    J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失...

    java视频学习总结

    Java Native Interface(JNI)提供了Java代码与本地代码交互的能力,使得Java应用程序可以利用系统级功能,或者调用已有的非Java语言编写的库,甚至是编写性能要求极高的代码段。 JNI的一个关键特性是其对Java...

    windows环境下32位汇编语言程序设计

    笔者从事汇编编程已经有十几年的历史了,从8086时代的DOS汇编编程开始到当前的Win32汇编编程,从一个初学者到现在能利用Win32汇编来解决大部分编程需求,中间也经过了很长时间的摸索和大量的挫折,所以笔者很清楚...

    Java参考大全

    ### Java参考大全知识点详解 #### 1. Java的起源与发展历程 ##### 1.1 Java的由来 Java 作为一种新兴的编程语言,其诞生...无论是从历史背景还是实际应用角度来看,Java 都是一个值得深入学习和掌握的重要编程语言。

    android反汇编2014最新版

    首先,我们来看"APK反编译工具包v1.6.rar"。这个工具包通常包含一系列用于反编译APK文件的实用程序,例如Apktool、dex2jar等。Apktool能够解包APK文件,将资源文件和XML布局还原为原始格式,便于分析和修改。而dex2...

    汇编语言程序 80x86

    整体来看,本书系统全面地介绍了80x86微型计算机的汇编语言及其程序设计技术,通过丰富实例和练习,非常适合初学者学习汇编语言基础,同时对于那些希望深入研究计算机技术的读者也是一本宝贵的参考资料。

    ctl.zip_java ctl

    从描述来看,这个压缩包中的内容是用户使用Java编写的一个可执行程序。 【描述】"我java编的一个运行程序" 暗示了这个压缩包内的主要目标是一个Java程序,它被设计为可以被运行,可能是控制台应用或者GUI应用。Java...

    masm汇编工具

    在软件开发中,尽管高级编程语言如C++、Java和Python等被广泛使用,但汇编语言在某些特定领域,如系统级编程、嵌入式系统和性能优化等方面,仍然扮演着重要角色。在Windows平台上,Microsoft汇编语言(MASM)是...

    Smali2Java.1.0.0.558

    接着,我们来看Smali2Java。这款工具正是为了简化这个过程而设计的,它能将Smali代码翻译回可读性较高的Java源码。1.0.0.558作为其最新版本,可能包含了性能优化、错误修复和新功能,以提升转换的准确性和用户体验。...

    Troubleshooting Guide for Java SE 6 with HotSpot VM

    虽然提供的文档内容部分不完整,但从标题和描述来看,可以推测出文档可能包含以下几方面的内容: 1. **常见问题及解决方案**:列出常见的故障现象及其对应的排查方法,帮助用户快速定位并解决问题。 2. **性能调优...

    未来汇编(工具)

    【标题】"未来汇编(工具)" 涉及到的是计算机编程领域中的汇编语言及其相关工具。汇编语言是一种低级编程语言,它与机器...对于希望深入硬件操作或优化性能的程序员来说,掌握汇编语言和相关工具是非常有价值的技能。

    《JAVA程序设计》模拟题带答案(C卷)汇编.pdf

    【JAVA程序设计】知识点详解 一、基础概念与特性 1. Java中的基本数据类型包括布尔型(Boolean),其中布尔变量的值只能是true或false,而不是0或1。 2. Java中的整型(int)大小是固定的,为32位,无论在哪个平台上...

    Google Andorid Dalvik JavaVM Kernel Code MIPS Version

    - 探索虚拟机与硬件之间的交互,以及如何通过汇编语言来提升性能。 - 分析和比较 MIPS 版本的 Dalvik 虚拟机与其他架构(如 ARM 或 x86)的实现差异。 对于希望深入理解 Android 系统、Dalvik 虚拟机工作原理或者 ...

    compile haskell to java

    为了更好地理解Haskell到Java的编译过程,我们来看一个具体的例子: 假设有一个简单的Haskell函数: ```haskell f x y = if x * g y ``` 该函数可以被解析并转换为抽象语法树,然后经过优化处理,最终生成Java...

    Java工程师面试题之三大框架[汇编].pdf

    首先,我们来看一下Hibernate。Hibernate是一个强大的对象关系映射(ORM)框架,它的主要工作原理包括:读取和解析配置文件,解析映射信息以创建SessionFactory,打开Session,创建事务,执行持久化操作,提交事务,...

Global site tag (gtag.js) - Google Analytics