《Java程序性能优化》读书笔记

很不错的书籍。值得反复阅读。附带下载地址

第一章 java性能调优概述

一般来说,程序的性能的表现方面:

  • 执行速度
  • 内存分配
  • 启动时间
  • 负载承受能力

性能参考指标:

  • 执行时间
  • CPU时间
  • 内存分配
  • 磁盘吞吐量
  • 网络吞吐量
  • 响应时间

木桶原理与性能瓶颈,最有可能成为性能瓶颈的环节:

  • 磁盘IO
  • 网络操作
  • CPU
  • 异常
  • 数据库
  • 锁竞争
  • 内存
    加速比=优化前系统耗时/优化后系统耗时
    Amdahl定律:
    加速比speedup<=1/(F+(1-F)/N)
    其中N为CPU处理器数量,F为系统内必须串行化的程序比重。由此可见,为了提高系统的运行速度,仅仅增加N,是不能提高运行速度的,从根本上修改程序的串行化行为,提高系统内并行模块的占比,才行。

性能调优层次:

  1. 设计调优
  2. 代码调优
  3. JVM调优
  4. 数据库调优:1. 应用层SQL优化;2.数据库优化;3.数据库软件优化;
  5. 操作系统调优:共享内存段、信号量、共享内存最大值shmmax、共享内存最小值shmmin、最大文件句柄数、虚拟内存大小、磁盘块大小。

第二章 设计优化

常用手段

  1. 善用设计模式
    1. 单例模式
    2. 代理模式
    3. 享元模式
    4. 装饰者模式
    5. 观察者模式
    6. value object模式
    7. 业务代理模式
  2. 常用的优化组件和方法
    1. 缓冲buffer,缓冲区是一块特定的内存区域;缓冲区不宜过大,浪费系统内存,增加GC负担;
    2. 缓存cache,WeakHashMap;EHCache数据缓存解决方案,OSCache,可用于缓存任何对象,JBossCache可用于JBoss集群间数据共享的缓存框架;EHCache的缺点是缓存组件和业务层代码紧密耦合,依赖性太强;基于动态代理的缓存;
    3. 对象复用-池:线程池,数据库连接池;适用场景:创建耗时的大对象,节省获取对象实例的成本,减少GC负担;生成实例成本小的对象,使用池的方式,得不偿失;JDK new操作的效率很高,但是new操作所调用的类的构造函数可能很耗时;apache commons-pool对象池组件,对象池接口ObjectPool,PoolableObjectFactory,内置三个对象池,StackObjectPool,GenericObjectPool,SoftReferenceObjectPool;
    4. 并行代替串行
    5. 负载均衡,Apache+Tomcat集群搭建负载均衡解决方案,Session共享模式,黏性Session模式和复制Session模式;跨JVM分布式缓存框架Terracotta,可以实现Tomcat的Session共享;
    6. 时间换空间,看系统的性能瓶颈是什么,空间是瓶颈,则采用时间换空间;
    7. 空间换时间

第三章 java程序优化

  1. 字符串优化处理
  2. 核心数据结构
  3. 使用NIO
  4. 引用类型
    1. 强引用
    2. 软引用
    3. 弱引用
    4. 虚引用
  5. 其他技巧
    1. 异常try…catch,慎用,循环中不能用;
    2. 使用局部变量;
    3. 位运算代替乘除法;
    4. 少用switch,尤其是分支多的情况;
    5. 一位数组代替二维数组,减少集合的方法调用;
    6. 提取表达式(重复的部分),尤其是遇到循环;
    7. 展开循环;
    8. 布尔运算代替位运算(条件判断&&||,断路原则);
    9. arrayCopy();
    10. 使用buffer进行IO操作;
    11. 使用clone()代替new;
    12. 静态方法代替实例方法;

String对象的3个特点:

  • 不变性;
  • 针对常量池的优化:当两个String对象拥有相同的值时,他们只是引用常量池的同一个拷贝;
  • 类的final定义;
    字符串分割与查找

第四章 并行程序开发优化

  1. 并行程序设计模式
    1. Future模式,即异步;
    2. master-worker模式,类似于fork-join,master进程负责接收和分配任务,worker进程负责处理子任务;
    3. Guarded Suspension模式,
    4. 不变模式,不变模式比只读属性具有更强的一致性和不变性,只读属性自身可能变化;不变模式的使用条件:1. 对象创建后,其内部状态和数据不再发生变化;2. 对象需要被共享,被多线程频繁访问。实现4要点:1. 去掉setter方法和所有修改自身属性的方法;2. 所有属性私有且final;3. 没有子类可以继承并重写其方法;4. 构造函数可以创建完整对象。
    5. 生产者-消费者模式;
  2. JDK多任务执行框架
    1. 无限制线程的缺陷
    2. 简单的线程池实现
    3. Executor框架
    4. 自定义线程池
    5. 优化线程池大小,估算公式:N = Nc * Uc * (1+W/C),其中Nc是CPU的数量,Uc是CPU的使用率,W/C是等待时间与计算时间的比率。
    6. 扩展ThreadPoolExecutor
  3. JDK并发数据结构
    1. 并发List
    2. 并发Set
    3. 并发Map
    4. 并发Queue
    5. 并发Deque
  4. 并发控制方法
  5. 锁性能与优化
  6. 无锁并行计算
  7. 协程

第五章 JVM调优

JVM 内存模型

  1. 程序计数器
  2. java虚拟机栈
  3. 本地方法栈
  4. java堆
  5. 方法区

JVM内存分配参数

  • 最大堆内存
  • 最小堆内存
  • 新生代
  • 持久代
  • 线程栈
  • 堆的比例分配

垃圾收集
垃圾收集器要处理的基本问题:

  1. 哪些对象需要回收?
  2. 何时回收这些对象?
  3. 怎么回收这些对象?

算法:

  • 引用计数法(reference counting):问题:循环引用;
  • 标记-清除算法(mark-sweep),两个阶段,可达性分析;问题:空间碎片,尤其是大对象的内存分配,不连续的内存空间的工作效率要低于连续的空间。
  • 复制(copy),代价:内存折半;其高效性建立在存活对象少、垃圾对象多的情况。
  • 标记压缩(mark-compact),将所有的存活对象压缩到内存的另一侧;
  • 增量(incremental collecting),垃圾回收时,stw,所有线程挂起;故,垃圾回收与应用程序交替执行;但是线程切换和上下文转换的消耗,使得GC的成本提高,吞吐量下降。
  • 分代(generational collecting)

垃圾收集器的类型
按线程数分,串行GC和并行GC;
工作模式分,并发式和独占式;
碎片处理方式分,压缩和非压缩;
工作的内存区间分,新生代和老年代;

评价GC策略的指标:

  • 吞吐量
  • 垃圾回收器负载
  • 停顿时间
  • 垃圾回收频率
  • 反应时间
  • 堆分配

新生代串行收集器:单线程、独占式,stop the world,client模式下默认的GC,没有线程切换的开销;
老年代串行收集器:标记-压缩,单线程、独占式,CMS的备用GC;
并行收集器:多线程,独占式,有线程切换的开销,线程数通过-XX:ParallelGCThreads指定,CPU<8,设置为GC数,CPU>8,设置为3+[(5*CPU_count)/8]

第六章 性能调优工具

1. Linux命令行

1. top
2. sar
3. vmstat
4. iostat
5. pidstat

2. Windows工具

任务管理器

perfmon性能监控工具

process explorer

加强版的任务管理器

pslist

基本用法:
pslist [-d] [-m] [-x] [-t] [-s [n]] [-r n] [name | pid]

3. JDK命令行

1. jps
2. jstat
3. jmap
4. jstack
5. jinfo
6. jhat
7. jstatd
8. hprof

4. JConsole

5. Visual VM多合一工具

6. Visual VM对OQL的支持

7. MAT内存分析工具

8. MAT对OQL的支持

9. JProfile

posted @ 2018-09-22 23:12  johnny233  阅读(8)  评论(0编辑  收藏  举报  来源