final的合理使用\n\nfinal修饰的 类不能被派生;方法不能被重写;变量不能被修改。\n\n基于这个特性,java会事先找出内联的所有方法,提高运行效率\n重用对象\n\n性能消耗:对象的生成 和 回收\n\n对于多个字符串的连接时尽量使用StringBuffer/StringBuilder\n少使用全局变量\n\n方法体内的局部变量及方法传递的参数会在栈中临时存储,方法调用结束后就会自动消除,不需要额外的回收消...
final修饰的 类不能被派生;方法不能被重写;变量不能被修改。
基于这个特性,java会事先找出内联的所有方法,提高<a href="#runtime" target="_self" rel="noopener noreferrer">运行</a>效率
性能消耗:对象的生成 和 回收
对于多个字符串的连接时尽量使用StringBuffer/StringBuilder
方法体内的局部变量及方法传递的参数会在栈中临时存储,方法调用结束后就会自动消除,不需要额外的回收消耗.
系统的I/O操作会很消耗系统性能,及时关闭会避免一些性能及不可预期的错误.
可重用的计算结果,与可在同一次遍历得出的结果可以合并在一起.
如 一些排序(一般是内置方法,可以自行定义)与循环取值计算的操作可以合并
在一些程序中会有不执行的语句,这些语句所使用的变量应该在语句内创建
Object o = new Object("eg");
if(exist){
String a = o.getName();
}else{
a = "";
}
//换成
Object o = new null;
if(exist){
o = new Object("eg");
String a = o.getName();
}else{
a = "";
}
异常对性能不利。抛出异常首先要创建一个新的对象,Throwable接口的构造函数调用名为fillInStackTrace()的本地同步方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,Java虚拟机就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。
异常只能用于错误处理,不应该用来控制程序流程。
集合的初始长度往往不能满足业务需求,而自动扩容又会消耗性能.
如果能够估计到集合的合理大小并设置初始大小,就可以避免集合的自动扩容所带来的消耗.
System.arraycopy:一维数组属性->值复制;一维数组对象->引用复制;二维数组->引用复制.
System.arraycopy是对内存直接进行复制,减少了for循环过程中的寻址时间,从而提高了效能(针对于深拷贝方式)
在计算机底层对位的操作是最快捷的,不需要对乘法或除法进行解析。
注意:java编译器会对*和%运算运行自动优化,不需要我们去考虑。而对于除法,在保证被除数不对负的情况下应该使用位移运算。
int val = 10;
//int a = val * 8;
int b = val / 4;
//改进为
int val = 10;
//int a = val << 3;
int b = val >> 2;
同步用HashMap,ArrayList,StringBuilder;异步用ConcurrentHashMap,Vector,StringBuffer.
基于对象的高复用。
pring的依赖注入模式即可看成是统一管理单例
实现了RandomAcecss接口的集合在随机访问时应使用for,顺序访问时应使用foreach。foreach使用iterator进行遍历。
略
节省创建连接和线程创建开销
带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大地提升IO效率
略
避免出现空指针异常
String a = "aaa";
if(a.equals("aaa"))
//do something
//改为
String a = "aaa";
if("aaa".equals)
//do something
String.valueOf()在底层会调用Integer.toString()但会做一个空判断。+操作符会先用append进行拼接,再用toString().
i.toString() > String.valueOf(i) > i + “”
Map.entrySet 进行值及键的遍历;使用Map.keySet()/values()进行键或值的遍历。
for(Map.Entry e : map.entrySet){
e.getKey();
e.getValue();
}
避免一个资源异常导致另一个正常资源不会被回收
对线程池/Session的重用会使一个线程使用多次,所以其local变量应该清理(会话清理)。
可读性和可编辑性增加
java编辑器不会对循环内的+字符串拼接进行优化。反而会不停地创建StringBuilder进行append(浪费内存)。
<hr>
语言无关的经典优化技术之一:公共子表达式消除<a href="#expression" target="_self" rel="noopener noreferrer">>>></a> 语言无关的经典优化技术之一:数组范围检查消除<a href="#array" target="_self" rel="noopener noreferrer">>>></a> 最重要的优化技术之一:方法内联<a href="#method" target="_self" rel="noopener noreferrer">>>></a> 最前沿的优化技术之一:逃逸分析<a href="#escape" target="_self" rel="noopener noreferrer">>>></a>
如果一个表达式E已经计算过了,并且从先前的计算到现在E中的所有变量值都没有发生变化,那么E的这次出现就成为了公共子表达式
eg: x = b * c + c * b;(如在这两个表达式之间c与b没有变化)则b * c就会被当作一个表达式E:
x = 2 * E;
java会对数组的访问进行越界判定,优化时jvm会对数组的数据流分析判定是否越界,以节省判定消耗。
java会把final方法调用使用内联的方式把被调用方的代码加入调用方里(由于多态的存在),以便节省方法寻找的消耗。
所以加为final的方法会被及时的找到并内联进方法会内。
jvm中为其他优化手段提供了分析技术。
逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中去,称为方法逃逸。甚至可能被外部线程访问到,比如赋值给类变量或可以在其他线程中访问到的实例变量,称为线程逃逸。
如果能证明一个对象不会逃移到方法外或者线程之外,也就是别的方法或线程无法通过任何途径访问到这个对象,则可能为这个变量进行一些高效的优化:
栈上分配
Java虚拟机中,对象在堆上分配这个众所周知。虚拟机的垃圾收集系统可以回收堆中不再使用的对象,但回收动作无论是筛选可回收对象还是回收和整理内存都要耗费时间。 如果确定一个对象不会逃逸出方法之外,那么让这个对象在栈上分配将会是一个不错的主意,对象所占用的内存空间就可以随着栈帧出栈而销毁,这样垃圾收集系统的压力将会小很多 同步消除
如果确定一个对象不会逃逸出方法之外,那么使用在该对象上的同步措施就可以被消除。 标题替换
标量:数据无法再次细分(元子数据,如基本数据类型)。对象则是可细分的,是聚合量。
如果确定一个对象不会逃逸出方法之外,则可以不创建对象,进而创建若干被这个方法使用的对象的成员变量。这些成员变量除了会被分配进栈里外,还会为后续优化作基础。
如果有需要,并且确认对程序运行有益,可以使用参数:
-XX:+DoEscapeAnalysis
来手动开启逃逸分析,开启之后可以通过参数:
-XX:+PrintEscapeAnalysis
来查看分析结果。有了逃逸分析支持之后,就可以使用参数:
-XX:+EliminateAllocations
来开启标量替换,使用参数:
-XX:+EliminatLocks
来开启同步消除,使用参数:
-XX:+PrintEliminateAllocations
查看标量的替换情况。
本站为非盈利网站,如果您喜欢这篇文章,欢迎支持我们继续运营!
本站主要用于日常笔记的记录和生活日志。本站不保证所有内容信息可靠!(大多数文章属于搬运!)如有版权问题,请联系我立即删除:“abcdsjx@126.com”。
QQ: 1164453243
邮箱: abcdsjx@126.com