java性能调优
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
13
性能优化模式 – 缓冲1
• 缓冲可以协调上层组件和下层组件的性能差,当上层组件 性能优于下层组件时,可以有效减少上层组件对下层组件 的等待时间
14
性能优化模式 – 缓冲2
• 生产者消费者模式
15
性能优化模式 – 缓冲3
• Java IO中读写文件缓冲,有无缓冲性能差为18倍(积分系 统中同样写一个77MB的文件,无缓冲18s,有缓冲1s)
6
性能优化模式
• • • • • • • • 设计模式 缓冲 缓存 池化 时空互换 并行化 协议优化 …
7
性能优化模式 – 单例模式
• 单例模式
减少频繁创建对象开销、减少内存消耗从而减轻GC压力
8
性能优化模式 – 代理模式1
• 延迟重量级对象创建,加快启动速度
9
性能优化模式 – 代理模式2
• 动态代理模式不同实现性能比较
40
JVM调优 – GC友好Tip
• ArrayList和LinkedList的删除元素方法,毋庸置疑LinkedList性能更 优 • ArrayList和LinkedList的遍历操作
不推荐使用for-each遍历 ArrayList推荐用for循环遍历(随机访问) LinkedList推荐用迭代器遍历,避免用for循环遍历,速度奇慢
32
代码调优 – 不变模式
• • • • 使用不变模式后,不变类的所有实例方法都不需要同步 JDK中的典型不变类String、Integer、Boolean等 不变类对象创建后,其内部状态不再发生变化 不变类必须保证下面4条
去除所有setter方法和所有修改内部状态方法 所有属性都用private final标记 确保没有子类可以重载修改它的行为 有一个可以创建完整对象的构造函数
33
代码调优 – 并发数据结构
• CopyOnWriteArrayList
读不加锁,写时先获取对象副本,再修改副本最后写回,写会加 锁 适合读远多于写或者遍历操作数量远多于可变操作数量的场景, 比如监听器列表
• CopyOnWriteSet • ConcurrentHashMap • ConcurrentLinkedQueue
• 持久代:-XX:PermSize、-XX:MaxPermSize • 线程栈:-Xss • 堆比例参数
-XX:SurvivorRatio = eden / s0 = eden / s1 -XX:NewRatio = 老年代 / 新生代
38
JVM调优 – GC算法
• Mark-Sweep算法:会导致不连续内存空间 • Copy算法:比Mark-Sweep高效,新生代GC算法 • Mark-Compact算法:基于Mark-Sweep改进的算法,第一阶 段Mark与Mark-Sweep基本相同,但第二阶段压缩存活对象 到内存一端,之后清理边界外的所有其他空间。老年代GC 算法
ASM方式实现的动态代理函数调用性能最高,但需要 对字节码很熟悉,并且不利于维护 JDK本身动态代理函数调用性能最差,而且不够灵活 JDK本身动态代理对象创建性能最高,因为使用native的 defineClass()方法 Java Assist和CGLib实现的动态代理函数调用性能优于 JDK动态代理,一般推荐用这两种实现动态代理
5
一些相关原理
• 80/20原则 • 木桶原理
系统最终性能取决于系统中性能最差的组件,应该关注性能最 差的组件。
• Amdahl定律
定义了串行化系统并行化后的加速比公式(加速比越大,系统 并行化优化效果越好): 加速比 = 优化前系统耗时 / 优化后系统耗时 假设加速比为Speedup,系统串行化比率(串行执行代码所占比 例)为F,CPU数目为N: Speedup <= 1 / (F + (1 - F) / N) 即当N一定时,F越小,加速比上限越大。
28
代码调优 – IO与NIO
• 标准IO包中的类不足以满足高效读写文件的目的,只有 BufferedReader、BufferedWriter、BufferedInputStream、 BuffredOutputStream四个类提供缓冲读写支持 • NIO包极大改善了这个局面,Buffer是NIO的一个核心类 • 如果涉及大文件随机读写,建议使用MappedByteBuffer和 RandomAccessFile
Java性能调优浅谈
@Will
1
提纲
• • • • • • 一些相关原理 性能测量指标 性能优化模式 代码调优 JVM调优 …
2
性能测量指标 - 1
• 各类资源消耗情况:
磁盘IO 内存占用 CPU 数据库 网络 锁竞争 …
3
性能测量指标 - 2
4
性能测量指标 - 3
比如用charAt代替startWith和endWith
• 涉及大量字符串拼接优先使用StringBuffer和 StringBuilder • 如果能预估字符串长度,最好提供容量参数
25
代码调优 – 数据结构1
• ArrayList和LinkedList的增加元素方法比较
add(E e):在末尾追加元素,ArrayList未必比LinkedList慢,如果ArrayList指 定了合适的capacity(capcity设置过小会频繁扩容) add(int index, E e):在指定位置插入元素,LinkedList性能优势开始凸显
11
性能优化模式 – 享元模式
• 与单例模式作用类似,避免对象重复创建 开销
12
性能优化模式 – Value Object模式
• RMI调用中将多个请求零散信息的请求合并 成只请求一个Value Object
比如请求订单信息场景,将getOrderId、getOrderNum等合 并成getOrder。Order就是Value Object。
• 其他最常用的两个指标(OLTP vs. OLAP)
吞吐量 延迟(或响应时间)
• 低延迟不一定意味着高吞吐量
从山西到广州运煤,一列火车100小时(包括往返)可以运输 10000t 煤,而一架飞机20小时(包括往返)可以运输100t煤。
• 并发度 = 吞吐量 * 延迟
比如一个系统处理某种任务的延迟为1ms,吞吐量为 1000tps, 那么并发度就为1/1000 * 1000 = 1,即单线程模型。
35
代码调优 – 其他小Tip
• 尽量使用JDK中提供的API,比如Arrays.sort、 System.arrayCopy(native方法) • 对于重量级对象创建可以用clone()代替new • 静态方法代替实例方法 • 嵌套循环中将忙循环放在内层 • …
36
JVM调优 – JMM
• • • • 程序计数器 Java虚拟机栈 本地方法栈(对应native方法) 堆
10
性能优化模式 – 代理模式3
• 动态代理模式的实际应用
Hibernate使用CGLib动态代理实现,达到延迟加载对象 的属性(延迟访问数据库)目的:HibernateProxy接口 CGLib的net.sf.cglib.proxy.LazyLoader 接口可以方便地用 于实现对象延迟加载
39
JVM调优 –Baidu NhomakorabeaGC相关参数
• 堆Dump:-XX:-HeapDumpOnOutOfMemoryError XX:HeapDumpPath=/var/heapdump • 获取GC信息:-verbose:gc或-XX:+PrintGC或XX:+PrintGCDetails,-XX:PrintHeapAtGC、XX:PrintGCApplicationStoppedTime • 类和对象跟踪:-XX:+TraceClassLoading、XX:+TraceClassUnloading • …
适用于高并发场景下的队列,无锁
• BlockingQueue
• …
34
代码调优 – 锁优化
• • • • • • 读写锁分离,ReadWriteLock 无锁化,ThreadLocal、CopyOnWriteArrayList(读)、ConcurrentLinkedQueue 减少锁粒度,ConcurrentHashMap分离锁 减少锁持有时间,最小化同步代码块 乐观CAS锁,AtomicInteger、AtomicLong、AtomicReference 自旋锁,JVM层面锁优化,-XX:+UseSpinning开启自旋锁
自旋锁使得在线程没有获得锁情况下不被挂起而是转去执行空循环 线程挂起、恢复开销很大 适用于访问共享资源时间较短情况
• •
锁消除,JVM层面锁优化,-server –XX:+DoEscapeAnalysis –XX:+EliminateLocks 开启 偏向锁,JVM层面锁优化,-XX:+UseBiasedLocking
16
性能优化模式 – 缓冲4
17
性能优化模式 – 缓存
• 本地缓存 • 分布式缓存
Redis、Memcached 避免缓存穿透,比如有大量的null请求穿透Cache,则 考虑为null也作Cache
• 程序的时间局部性原理
18
性能优化模式 – 池化
• 如果一个类的实例对象被频繁使用,那么不必每次都生成 新实例,可以将这些类的实例保存在一个池中,可以大大 减轻创建对象和销毁对象开销
26
代码调优 – 数据结构2
• HashMap和HashSet
哈希算法是否高效是性能的关键 良好的哈希算法除了函数本身运行性能高效外,还必 须满足尽量均匀地将值分散到哈希地址空间,并且哈 希冲突尽可能少
27
代码调优 – 异常开销
• 异常很方便,开销也很大
主要是Throwable的构造函数调用了fillInStackTrace() 方法构建异常栈,如果异常层次一深开销就更大了 避免不必要的异常(如异常被用作正常业务流程控 制) 避免在循环体内使用try-catch 重写fillInStackTrace()方法,提供空实现
数据库连接池 线程池 对象池
19
性能优化模式 – 时空互换1
• 时间换空间
内存资源紧张 实例:不使用第三个变量交换两个变量
20
性能优化模式 – 时空互换2
• 空间换时间
最常见 常用算法:缓存、Hash、查表法 … 实例:计算一个字符串数组中出现次数最多的字符串
21
性能优化模式 – 并行化
• 多进程 • 多线程:
线程池最佳线程数目 =(线程等待时间与线程CPU时间
之比 + 1)* CPU数目
• 实例 :
从磁盘串行和并行读取 30 张大小为 256K 的缩略图, 磁盘IO速度为 30 MB/s,磁盘每次寻道耗时 10 ms
22
性能优化模式 – 协议优化
• 各种序列化协议时间和空间对比
23
代码调优 – 字符串 1
• JDK 1.6的substring方法存在内存泄露风险, JDK 1.7已修复
24
代码调优 – 字符串2
• 字符串分割:优先使用StringTokenizer而不是String 类的split方法 • 在性能敏感代码中优先使用String类的charAt和 indexOf方法
29
代码调优 – 并发编程模式
• • • • • 生产者消费者模式(略) Future模式 Master-Worker模式 不变模式 …
30
代码调优 – Future模式
• Future模式的优势:在耗时任务执行的同时可以 去执行其他操作
31
代码调优 – Master-Worker模式
• 包含一个Master线程和多个Worker线程,Master线程接收用户请求、协调 Worker线程并整合最终处理结果。多个Worker线程协作处理用户请求。JDK 7 开始提供了fork/join框架。
分代:新生代(Eden、s0、s1)、老年代
• 方法区
又称永久区或持久代,主要存放常量信息和类信息 Hot Spot虚拟机中方法区也会进行GC
37
JVM调优 – JVM内存分配参数
• 堆内存:-Xmx、-Xms • 新生代:-Xmn,一般设置为整个堆空间的1/4到1/3
Hot Spot虚拟机中-XX:NewSize、-XX:MaxNewSize