Java 程序优化 (读书笔记)

--From : JAVA程序性能优化 (葛一鸣,清华大学出版社,2012/10初版)java

 

1. java性能调优概述ios

    1.1 性能概述 程序员

        程序性能: 执行速度,内存分配,启动时间, 负载承受能力。web

        性能指标: 执行时间,CPU时间,内存分配,磁盘吞吐量,网络吞吐量,响应时间。 算法

        优化策略: 木桶原理,优化性能瓶颈。数据库

    1.2 性能调优的层次设计模式

        设计调优,数组

        代码调优,浏览器

        JVM调优,缓存

        数据库调优,

        操做系统调优。

        

2. 设计优化

    2.1 善用设计模式 

        单例模式: 对于巨大对象,节省建立对象的时间空间;

        代理模式: 可用于延迟加载,提高系统启动速度;

        享元模式: 对象和组件复用,节省建立对象的开销;

        装饰者模式: 分离组件,提升可维护性增长模块复用性;

        观察者模式: 避免新开线程循环等待;

    2.2 经常使用组件优化

        缓冲(漏斗设计), 

        缓存(空间换时间), 

        对象复用“池”, 

        并行代替串行,

        负载均衡(Terracotta), 

        时间换空间,

        空间换时间。

        

3. Java程序优化

    3.1 字符串 

        不变性, 针对常量池优化

        subString 空间换取时间

        split 正则分割

        StringTokenizer 字符串分割

        灵活使用charAt 和 indexOf

        StringBuffer(线程安全) 和 StringBuilder : 初始化时设置最大容量

    3.2 核心数据结构

        List : ArrayList 和  LinkedList

        Map  : Hashtable(线程安全), HashMap, LinkedHashMap, TreeMap(可排序)

        Set  : hashSet, linkedHashSet, TreeSet

        集合访问优化 :

            分离循环中被重复调用的代码 ( i<collection.size() -> i<collectionSize )

            省略相同的操做 (循环内部的声明)

            减小方法调用 (优先直接访问内部变量)

        RandomAccess (随即访问): ArrayList Vector

    3.3 使用NIO提高性能

        NIO的Buffer 和 Channel 配合使用

        Buffer的原理和相关操做

        Buffer内存缓存和堆上内存区别

    3.4 引用类型

        强引用 : 能够直接访问,不会被GC回收,可能致使内存泄露(互相引用)

        软引用 : SoftReference<T> 内存紧张,会被GC回收

        弱引用 : WeakReference<T> GC发现当即回收

        虚引用 : PhantomReference<T> 始终返回null

        WeakHashMap : 弱引用的 HashMap

    3.5 改善性能

        慎用异常,try catch浪费性能 (62ms/110ms)

        使用局部变量,栈的访问比堆快 (78ms/266ms)

        位运算代替乘除法            (31ms/219ms)

        一维数组代替二维数组        (235ms/344ms)

        提取公共表达式

        下降循环次数 如数组赋值 i++ -> i+=3 (31ms/94ms)

        布尔运算代替位运算 (逻辑运算中布尔运算快于位运算,越简单的越靠前)

        使用System.arrayCopy()(native 函数)复制数组(31ms/250ms)

        Buffer进行I/O操做

        使用clone()代替new (通常是浅拷贝,其余须要具体实现clone)

        静态方法代替实例方法

        

4. 并行程序开发及优化

    4.1 并行程序设计模式

        Future 模式 : 提升响应速度

        Master_worker 模式 : 子任务分配,提升响应速度 

        Guarded Suspension 模式 : 队列缓冲,非当即处理,避免由于请求太多而崩溃

        不变模式 : 相似String/Double...不须要同步,线程安全

        生产者消费者模式 : 缓解二者间的性能差

    4.2 JDK多任务执行框架

        无限制线程的缺陷

        简单的线程池

        Exector 框架

        自定义线程池 : ThreadPoolExecutor

        优化线程池大小 : n = Ncpu * Ucpu *(1 +W/C)

        扩展 ThreadPoolExector

    4.3 JDK并发数据结构

        并发 list : CopyOnWriteArrayList

        并发 Set : CopyOnWriteArraySet

        并发 Map : ConcurrentHashMap

        并发 Queue : ConcurrentLinkedQueue (使用CAS无锁) / LinkedBlockingQueue

        并发 Deque : LinkedBlockingDeque (读写都加锁)

    4.4 并发控制方法 

        Java内存模型与 volatile

        同步关键字 synchronized

        ReentrantLock 重入锁

        ReentrantReadWriteLock 读写锁 (并读串写)

        Condition 对象

        Semaphore 信号量 (限制最大访问线程数)

        ThreadLocal 线程局部变量

    4.5 锁的性能和优化

        线程的开销

        避免死锁

        减少锁持有时间

        减少锁粒度

        读写分离锁来替换独占锁

        锁分离 (LinkedBlockingQueue)

        重入锁 (ReentrantLock) 和内部锁(Synchronized)

        锁粗化 Lock Coarsening (屡次重复请求消耗资源)

        自旋锁 Spinning Lock (执行空循环来减小被挂起的次数)

        锁消除 Lock Elimination (消除没必要要的锁)

        锁偏向 Biased Lock (高并发效率低)

    4.6 无锁的并行计算

        非阻塞的同步/无锁 (基于CAS)

        原子操做 (java.util.concurrent.atomic)

        Amino 框架 : 提供现成安全的,基于无锁的数据结构,内置了多线程调度模式。 

        Amino 集合 : LockFreeList(linked)/LockFreeVector(ArrayList); LockFreeSet

        Amino 树 : LockFreeBSTree(二叉搜索树)

        Amino 图 : UndirectedGraph<E> / DirectedGraph<E>

        Amino 简单调度模式 : Master_worker (静态/动态)

    4.7 协程

        协程的概念 : 进程的分割式线程,线程的分割是协程 

        Kilim 框架 : 当须要大量线程时,使用协程能提升性能,下降线程维护切换的性能

 

5. JVM调优

    5.1 Java 虚拟机内存模型

        程序计数器 : 线程私有的内存空间,互不影响; 当执行java方法,程序计数器为Java字节码地址,当执行native方法程序计数器为空

        Java虚拟机栈 : 线程私有的内存空间, 用于管理Java函数调用, -Xss1M

        本地方法栈 : 管理本地方法调用

        Java堆 : 分为新生代和老年代两部分

        方法区 : 和Java堆同样被全部线程共享;包括类的类型信息,常量池,域信息,方法信息,也叫永久区

    5.2 JVM 内存分配参数

        -Xmx : 设置最大堆内存

        -Xms : 设置初始堆内存

        -Xss : 设置线程栈 (使用系统内存,堆空间分配越大,线程总数越少) JDK5.0之后每一个线程堆栈大小为1M,之前每一个线程堆栈大小为256K

        -Xmn : 设置新生代 (通常为堆空间的1/4~1/3 )

        -XX:NewSize : 设置初始新生代空间

        -XX:MaxNewSize : 设置最大新生代空间    

        -XX:PermSize : 设置初始持久区

        -XX:MaxPermSize : 设置最大持久区

        -XX:SurvivorRatio 设置新生代比例 (eden : survivor) 

        -XX:NewRatio : 设置heap比例 (老年代 : 新生代) 

        -XX:TargetSurvivorRatio : 设置suvivior使用率,超过空间会送入老年代

    5.3 垃圾收集基础

        垃圾收集的做用

        垃圾收集算法与思想 

            1) 引用计算法 : 记录对象引用数,但两个对象的循环引用会致使内存泄露

            2) 标记清除法 : 记录根节点开始的可达对象,但回收后形成空间碎片

            3) 复制算法 : 在存活对象少垃圾多的状况下,系统空间折半,复制有效对象到另外一空间,适用于新生代对象(from space to space)

            4) 标记压缩算法 : 在存活对象多垃圾少的状况下,清除无效对象,压缩有效对象,清除空间碎片,适用于老年代

            5) 增量算法 : 避免长时间占据应用程序执行时间,而交替执行,每次清理一小片内存空间,但因为线程频繁上下文切换,会下降系统吞吐量

            6) 分代 : 分为年轻代和老年代,分别使用不一样的垃圾收集算法,新生代使用复制算法,老年代使用标记压缩算法

        垃圾收集器的类型 

            线程数 : 串行/并行

            工做模式 : 并发/独占

            碎片处理 : 压缩/非压缩

            分代 : 新生代/老年代 

        评价GC策略的指标 : 吞吐量/垃圾回收器负载/停顿时间/垃圾回收频率/反应时间/堆分配

        新生代串行收集器 : 单线程,独占

        老年代串行收集器 : 标记压缩,串行独占

        并行收集器 : 多线程,独占

        新生代并行回收收集器 : 多线程,独占,关注系统吞吐量

        老年代并行回收收集器 : 标记压缩,关注系统吞吐量

        CMS(concurrent Mark Sweep)收集器 :  标记清除法,多线程并行,非独占

        G1(Garbage First)收集器 : 关注吞吐量和停顿控制,适用标记压缩法

        Stop the World : 整个应用中止等待垃圾回收完成

        收集器对系统性能的影响

        GC相关参数总结

            1) 串行回收器相关参数

                -XX:+UseSerialGC : 新生代串行收集器和老年代串行收集器

                -XX:SurvivorRatio : 设置eden和survivor的比例

                -XX:PretenureSizeThreshold : 设置大对象进入老年代的阈值,对象大小超过此值,直接在老年代分配,只对串行收集器和新生代并行收集器有效,并行回收收集器不识别此参数

                -XX:MaxTenuringThreshold : 设置进入老年代的年龄最大值,每次Minor gc后,对象年龄+1, 默认15

            2) 并行回收器相关参数

                -XX:+UseParNewGC : 新生代使用并行收集器

                -XX:+UseParallelOldGC : 老年代使用并行回收收集器

                -XX:ParallelGCThreads : 垃圾回收线程数

                -XX:MaxGCPauseMillis :  最大垃圾收集停顿时间

                -XX:GCTimeRatio : 设置吞吐量大小n, GCTime < 1/(1+n)

                -XX:+UseAdaptiveSizePolicy : 打开自适应GC策略,新生代大小,eden和survivor比例等自动调整

            3) 与CMS回收器相关参数

                -XX:+UseConcMarkSweepGC : 新生代使用并行收集器,老年代使用CMS+串行收集器

                -XX:parallelCMSThreads : CMS的线程数量

                -XX:CMSInitiatingOccupancyFraction : 设置CMS收集器在老年代空间使用多少后触发,默认68%

                -XX:+UseCMSCompactAtFullCollection : 设置CMS收集器在完成垃圾收集后是否进行一次内存碎片整理

                -XX:CMSFullGCsBeforeCompation : 设置多少次CMS垃圾回收后进行内存压缩

                -XX:+CMSClassUnloadingEnabled : 容许对类元数据进行回收

                -XX:+CMSParallelRemarkEnabled : 启用并行标记

                -XX:CMSInitiatingPermOccupancyFraction : 永久区达到此阈值,启动CMS回收(前提是  -XX:CMSClassUnloadingEnabled激活)

                -XX:UseCMSInitiatingOccupancyOnly : 达到阈值才进行CMS回收

                -XX:+CMSIncrementalMode : 使用增量模式,适合单CPU

            4) 与G1回收器相关参数

                -XX:+UseG1GC : 使用G1回收器

                -XX:+UnlockExperimentalVMOptions : 容许使用实验性参数

                -XX:MaxGCPauseMillis : 设置最大垃圾停顿时间

                -XX:GCPauseIntervalMillis :  设置垃圾收集间隔时间

            5) 其余参数

                -XX:+DisableExplicitGC : 禁用显示GC

    5.4 经常使用调优案例和方法

        1) 将新对象预留在新生代 : 新生代的垃圾回收速度高于老年代回收,可设置新生代大小或者新生代和老年代比例调整新生代大小

        2) 大对象进入老年代 : 大对象须要空间,可能致使空间不足或者须要移动大量小对象到老年代,设置-XX:PretenureSizeThreshold

        3) 设置对象进入老年代的年龄 : gc一次年龄+1,年龄到达阈值进入老年代,设置阈值 -XX:MaxTenuringThreshold

        4) 稳定与震荡的堆大小 : 空间大GC速度慢,空间小GC速度快,大部分设置最大最小相同

            -XX:MinHeapFreeRatio : 设置堆空间最小空闲比例,默认40;

            -XX:MaxHeapFreeRatio : 设置对空间最大空闲比例,默认70;

        5) 吞吐量优先案例 : java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC

        6) 使用大页案例 : java -Xmx2506m -Xms2506 -Xmn1536m -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:LargePageSizeInBytes=256m (设置大页大小)

        7) 下降停顿案例 : java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC _XX:+UseParNewGC -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31

    5.5 实用JVM参数

        1) JIT(Just-In-Time)编译参数 : 运行时,函数运行次数超过阈值,将字节码编译成本地代码提升执行效率,

            -XX:CompileThreshold : 编译阈值

            -XX:+PrintCompilation : 打印JIT编译信息

            -XX:+CITime 打印JIT编译的基本信息

        2) 堆快照(堆Dump) : 发生OOM时导出Dump文件,可使用Visual VM等工具分析

            -XX:+HeapDumpOnOutOfMemoryError : 发生OOM时导出当前堆快照

            -XX:HeapDumpPath : 指定堆快照信息保存文件位置

        3) 错误处理 : 发生OOM时运行第三方脚本

            -XX:OnOutOfMemoryError=c:\reset.bat

        4) 取得GC信息

            -verbose:gc

            -XX:+PrintGC

            -XX:+PrintGCDetails

            -XX:+PrintGCTimeStamps : 打印每次GC的发生时间

            -XX:+PrintTenuringDistribution : 察看新生对象晋升老年代的实际阈值

            -XX:+PrintHeapAtGC : 每次GC打印堆的使用状况

            -XX:+PrintGCApplicationStoppedTime : 显示应用程序在GC发生时的停顿时间

            -XX:+PrintGCApplicationConcurrentTime : 应用程序在GC停顿时间的执行时间

            -Xloggc:C:\gc.log : GC日志

        5) 类和对象跟踪

            -XX:+TraceClassLoading : 跟踪类加载状况

            -XX:+TraceClassUnloading : 跟踪类的卸载状况

            -verbose:class :  跟踪类的加载和卸载状况

            -XX:+PrintClassHistogram : 当按下Ctrl + Break,输出系统内类的统计信息

        6) 控制GC

            -XX:DisableExplicitGC : 禁止显示GC操做,避免程序员大量使用System.gc()下降程序性能

            -Xnoclassgc : 禁止回收类(class,而不是对象实例)

        7) 选择类校验器

            -XX:-UseSplitVerifier :实用旧的类校验器,JDK1.6默认开启新的类校验器

            -XX:-FailOverToOldVerifier : 关闭再次校验功能, 默认新的校验器失败会再次使用老的校验器

        8) Solaris下线程控制

            -XX:+UseBoundThreads : 绑定全部用户线程到内核线程,减小线程进入饥饿状态的次数

            -XX:+UseLWPSychronization : 使用内核线程代替线程同步

            -XX:+UseVMInterruptibleIO : 容许运行时中断线程

        9) 使用大页

            -XX:+UseLargePages : 启用大页

            -XX:LargePageSizeInBytes : 指定大页的大小

        10) 压缩指针

            -XX:+UseCompressedOops : 打开指针压缩,压缩class的属性指针(静态成员),对象的属性指针,普通对象的每一个元素指针, 能节省内存,可是会消耗必定的性能

    5.6 实战JVM调优

        1) Tomcat简介与启动加速 : 减小GC次数,扩大新生代,禁止显示调用GC

        2) 一个示例web : 每一个用户分配1m空间

        3) JMEter介绍和使用 : 基于java的性能测试和压力测试工具,生成包括响应时间,错误数和吞吐量的报告

        4) 调优前Web应用运行情况 : GC过多,吞吐量为38.7/s

        5) 调优过程 : 肯定堆内存大小,合理分配新生代和老年代,肯定永久区大小,选择垃圾收集器,对垃圾收集器设置,禁用显示gc,进用类元数据回收,禁用类验证等

            设置堆空间和永久区,禁用显示gc,去掉类验证,吞吐量为47.9/s

            -Xmx512M(-Xmx256M)

            -Xms512M

            -XX:permSize=32M

            -XX:MaxPermSize=32M

            -XX:+DisableExplicitGC

            -Xverify:none

            使用并行回收收集器,吞吐量为51/s

            -XX:+UseParallelGC

            -XX:+UseParallelOldGC

            -XX:ParallelGCThreads=8

6 Java性能调优工具

    6.1 Linux命令行工具

        1) top : 显示系统中各个进程的资源占用情况

        2) sar : 周期性对内存,I/O和CPU状况采样 

        3) vmstat : 统计CPU内存使用状况,swap使用状况,可指定周期性采样和次数

        4) iostat : 提供详尽的I/O信息,可指定周期性采样和次数

        6) pidstat : 监测进程和线程的状况,

            监测CPU : 能够配合 jstack -l $ThreadId 察看进程堆栈

            I/O使用监控 

            内存监控

    6.2 Windows工具

        1) 任务管理器 

        2) perfmon性能检测工具 : 能够针对一个进程进行监控

        3) Process Explorer : 需安装

        4) pslist  : 需安装

    6.3 JDK命令行工具

        1) jps : 相似Linux下的ps,用于列出Java进程,-m(主函数的参数),-l(主函数路径),-v(显示JVM参数)

        2) jstat : 观察Java应用程序运行时的信息

        3) jinfo : 察看Java应用程序的扩展参数(JVM参数),可经过此命令来查看默认参数值,可修改参数 

        4) jmap : 生成堆快照和对象的统计信息

        5) jhat : 分析Java应用程序的对快照内容,可在浏览器中访问http://127.0.0.1:7000

        6) jstack : 导出Java应用车功能需的线程堆栈

        7) jstatd : RMI的服务端程序,创建远程监控通讯,须要使用java的安全策略在使用

        8) hprof : 非独立监控工具,用于监测Java程序的CPUh和堆信息,监控函数运行时间,导出程序堆内容

    6.4 JConsole工具 : %javahome%/bin/jconsole.exe

        1) JConsole链接Java程序 : 添加启动参数可远程链接

            -Dcom.sun.management.jmxremote.authenticate=false  -Dcom.sun.management.jmxremote.ssl=fals  -Dcom.sun.management.jmxremote.port=9988 -Dcom.sun.management.jmxremote

        2) Java程序概况 : 可查看堆内存,系统线程数量,加载类数量和CPU使用率

        3) 内存监控 : 察看内存详细信息,细化到eden,survivior,老年代,永久区;能够强制Full GC

        4) 线程监控 : 能够监测到全部线程以及栈信息

        5) 类加载状况 : 显示加载空间,类数量

        6) 虚拟机信息 : 显示虚拟机类型,版本,堆信息,虚拟机参数

        7) MBean管理 : 可操做GC信息显示,线程信息查看,峰值线程数量,当前线程数量,死锁检测等 

        8) 使用插件 : 如JDK自带插件JTop,察看线程CPU使用排序

    6.5 Visual VM多合一工具

        1) Visual VM链接应用程序 : 添加JVM参数或者配合jstatd远程监控

        2) 监控应用程序概况 : 相似Jconsole

        3) Thead Dump和分析 

        4) 性能分析 : 在Sampler页面下,能够监测方法调用时间

        5) 快照 : 快照导出 

        6) 内存快照分析 

        7) MBean管理 : 可经过插件继承MBean

        8) TDA使用 : 分析导出的线程快照,能够单独运行,也能够做为Visual VM插件运行

        9) BTrace介绍 : 在不停机的状况下添加代码执行,

            监控指定函数耗时 

            取得任意行代码信息

            定时触发

            监控函数参数

            监控文件

    6.6 Visual VM对OQL的支持

        1) Visual VM的OQL基本语法

        2) 内置head对象 

        3) 对象函数

        4) 集合/统计函数 

        5) 程序化OQL

    6.7 MAT内存工具分析

    6.8 MAT对OQL的支持

    6.9 JProfile简介 : 商业软件

    

        

JVM :      -XX:+UseSpinning (开启自旋锁) -XX:PreBlockSpin (自旋锁的等待次数)        

        -server -XX:+DoEscapeAnalysis (逃逸分析) -XX:+EliminateLocks (锁消除)

        -XX:+UseBiasedLocking (开启偏向锁)

        -Xss1M

        -XX:+PrintGCDetails(输出收集器日志)

        -XX:+UseSerialGC (新生代串行收集器和老年代串行收集器)

        -XX:+UseParallelGC (新生代并行回收收集器和老年代串行收集器,会中止app threads)

        -XX:+UseParNewGC (新生代并行收集器和老年代串行收集器)

        -XX:+UseConcMarkSweepGC (新生代并行收集器和老年代CMS)

            -XX:CMSInitiatingOccupancyFraction (CMS老年代回收阀值n,默认68(%),若是内存使用增加快,n较小时效率高,反之n应该较大)

            -XX:+UseCMSCompactAtFullCollection (CMS收集完成进行碎片整理,整理不是并发进行)

            -XX:CMSFullGCsBeforeCompation (CMS进行n次后,才进行内存压缩)

        -XX:+UseParallelOldGC (新生代老年代并行回收处理器) 

            -XX:MaxGCPauseMillis (最大垃圾收集停顿时间) 

            -XX:GCTimeRatio (设置吞吐量大小 : n=[0~100] (gcTime <= 1/(1+n) ) ) 

            -XX:+UseAdaptiveSizePolicy (自适应GC调节策略) 

            -XX:ParallelGCThreads (收集器线程数,通常等于CPU数量)

        -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC (启动G1 GC)

            -XX:MaxGCPauseMillis -XX:GCPauseIntervalMillis (不超过200ms, 停顿不超过50ms,参数只是目标,不保证执行)

        -XX:DisableExplicitGC (禁用显示gc) -Xnoclassgc(禁用类元数据回收) -Xverify:none (禁用类验证)

        

        

remote debug : 远程debug 

    远程debug顾名思义,可以将远程操做系统上的任何java进行debug,可是有前提是本地须要有同步的代码。

    1.远程debug的步骤是在远程操做系统上启动java进程时增长特殊的

        -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=9977

    2.在Eclipse中新建一个Remote Java Application

相关文章
相关标签/搜索