zoukankan      html  css  js  c++  java
  • java程序性能优化

     

    Java程序调优入门级教程,看似很厚,其实书很薄,国内高手写的,当然有一些内容有抄袭的嫌疑,适合java开发经验不太足的,一般的高手,此类技能应该必须具备了。我看的时候花了两周,总结起来如下,纯干货(不包括JVM部分,因为个人觉得JVM学习看《深入理解Java虚拟机》):

     

    1.常见的系统瓶颈因素:磁盘I/O,网络操作,CPU,java异常捕获及处理,数据库读写,锁竞争,GC

    2.加速比Speedup<=1/(F+(1-F)/N),F为串行计算的比例,NCPU逻辑数

    3.调优层次:设计调优--->代码调优--->JVM参数调优--->数据库调优--->OS调优,当实际应用出现瓶颈需要调优时,一般的步骤是:代码--->JVM参数--->数据库--->OS--->应用架构(设计)

    4.设计调优的常见招数:

            1:多用设计模式(单例,享元,观察者,访问者,装饰者,代理等)

            2Buffer/Cache,缓冲/缓存思想

            3:多线程并行代替串行(要求一般串行间没有因果或前后关系)

            4:应用负载均衡(JVM,需要处理好共享数据的一致性问题)

            5:时间/空间的转换

            6:使用ValueObject减少计算或请求次数

    5.代码优化的几个简单切入点:

            0):不要在循环体里定义引用并创建对象,将定义引用放到外面

            Object obj = null;

    for (int i = 0; i < 10000; ++i) {

       (Object) obj = new Object();

        System.out.println("obj= "+ obj);

    }

    1):避免重复初始化对象

    public class A {

        private Hashtable table = new Hashtable ();

        public A() {        

            table = new Hashtable(); // Hashtable对象table初始化了两次

        }

    }

            1):字符串优化的几个地方

                    a:substring()方法速度很快,但是容易引起内存溢出问题,因为会保留对原串的引用,所以建议用new String(***.substring(参数))的模式

                   b:对字符串截取可用split,但速度快的可以考虑StringTokenizer(sun不建议使用),最好用indexOf+substring自己实现截取

                    c:对字符串的开头/结尾子串判断一般用startsWith/endsWith,由于他们和split一样是基于正则的,所有最好用charAt来自己实现更快

                    d:对字符串的相加,StringBuild最优,StringBuffer次之(线程安全),String.concat再次之,+/+=最次(不考虑静态常量编译器的优化)

            2)ArrayList(Vector)LinkedList比较

                    a:ArrayList基于数组(一块连续的内存空间),LinkedList基于双向链表,因此ArrayList的主要性能耗在扩展空间时数据复制,LinkedList耗在数据遍历(尤其是找中间的数据)

                    b:头尾的新增/删除对LinkedList没有压力,但是每次随机访问需要从头查找,会要亲命

                    c:在尾部添加对ArrayList没有压力,但从头部删除都会数组复制,会要亲命。

                    d:LinkedList的遍历,要么用for-Each,要么Iterator,不要用普通的ini i=0;i<size;i++,因为get(i)是随机查找,每次都从头或尾遍历,会要亲命

                    e:一般实现了RandomAccess接口的类如ArrayListVector才可以在遍历时放心使用get,而且遍历时要尽量减少重复的获取size或元素,用临时变量缓存之

            3)HashMap如果key是一个个重写了hashCode方法的对象,如果此hashCode方法放回相同的int值,则每次放入不同对象会到同一个桶下,遍历查找很慢

            4)HashMap底层用了数组实现,使用大于等于initialCapacity并且是2的指数次幂作为数组大小,threshold为当前数组总容量与负载因子的乘积,即阀值,当实际容量超阀值        时会进行数组扩展复制,因此适当的initialCapacity有利于提高性能。

            5)LinkedHashMap基于元素进入顺序或被访问先后顺序(被访问的元素放到最后),TreeMap基于传入的Comparetor参数或实现了Comparablekey对象进行排序,适用范围        不一样。HashSet,LinkedHashSet,TreeSet是对应Map的简单封装。

            6):使用NIO(ByteBuffer+Channel)可以提升I/O读写速率,注意duplicate(),asReadOnlyBuffer(),slice()都是共享原始缓存数据的,一般用文件内存映射MappedByteBuffer,结构       化散射接口ScatteringByteChannel,结构化聚集接口GatheringByteChannel将多个ByteBuffer组成一个数组一次写入,用DirectBuffer代替ByteBuffer进行多次读写都可以提高效   率,但DirectBuffer是直接开辟OS内存,如果频繁新建回收,性能反而不如ByteBuffer虚拟机内的相同操作.

            7)4个引用级别:强,软,弱,虚,其作用分别不同,一般软和弱引用可以作为缓存的一种方案避免内存溢出,而虚更多用于跟踪对象回收时机,弱引用WeakHashMap可以        作为简单的缓存对象。

            8):不在循环代码中使用try-catch,尽量放到循环体外,多用局部变量或临时变量存储计算值以避免重复计算,可以考虑在一次循环中做多个操作减少循环次数(i+1,i+2,i+3...),        "阻断性"逻辑运算如&&来代替位运算如&(当然一般也不建议利用条件判断来做一些操作,因此后面的判断默认应该可以不去运行的)

            9):多用一维数组代替二维数组;使用Buffer进行I/O;对构造成本大的函数,用clone代替new(注意该类实现Cloneable,并且默认是浅复制,深复制需要自己重写Objectclone        方法)

            10):技巧:用位运算代替2次幂的乘除;多用static静态方法而不是实例方法;多用native方法如arrayCopy;

     

     

     

     

     

     

     

     

     

     





  • 相关阅读:
    安装lnmp 时如何修改数据库数据存储地址及默认访问地址
    ubuntu 设置root用户密码并实现root用户登录
    解决ubuntu 远程连接问题
    linux 搭建FTP服务器
    PHP 根据ip获取对应的实际地址
    如何发布自己的composer包
    使用composer安装composer包报Your requirements could not be resolved to an installable set of packages
    laravel 框架配置404等异常页面
    使用Xshell登录linux服务器报WARNING! The remote SSH server rejected X11 forwarding request
    IoTSharp 已支持国产松果时序数据库PinusDB
  • 原文地址:https://www.cnblogs.com/dimmacro/p/4460147.html
Copyright © 2011-2022 走看看