11_性能问题

性能问题

一、性能优化

1.1 目的

  • 提高程序的整体运行性能

1.2 原则

  • 始终把安全性放在第一
  • 程序正确后,再想办法提高运行速度

1.3 指标

  • 吞吐率优化:更有效地利用现有资源,用同样的资源做更多的事
  • 可伸缩性优化:当增加新资源时,新资源可以得到利用,程序的性能可以提升

1.4 权衡因素

  • 进行性能优化时,一定要有明确的性能需求,清楚了解什么时候优化,什么时候不优化
  • 必须以测试为基准,验证性能的优化程度,不要靠猜测
  • 做出性能优化决策时,必须考虑以下问题:
    • 做了什么优化?优化了什么地方?
    • 在什么样的场景下优化了?其他场景是否使用?
    • 优化的场景发生概率如何?
    • 这种优化会带来哪些问题?需要付出什么代价?例如增加开发风险或维护开销?
  • 避免不成熟的优化,一定要预估优化风险,以及验证优化结果

二、线程开销

2.1 上下文切换

  • 线程调度,会引起上下文切换
  • 上下文切换,会涉及到应用程序、JVM、操作系统等多方面的切换开销
  • 在 JVM、操作系统上消耗的时间越多,应用程序可用时间越少
  • 上下文切换的开销与平台有关,在大多数处理器中,上下文切换开销相当于 5000 ~ 10000 个时钟周期
  • 线程数量越多(竞争)、IO阻塞越多(挂起),上下文切换越频繁

2.2 内存同步

  • 同步实现会使用到特殊的硬件指令,比如内存栅栏,它有刷新缓存使得缓存无效、停止执行管道、禁止指令重排序等功能
  • 同步需要锁定共享内存总线,而所有处理器都共享这条总线,所以同步期间会影响其他线程的性能

2.3 阻塞

  • 阻塞会导致线程挂起,从而产生上下文切换
  • 阻塞挂起至少会引起2次上下文切换,一次是挂起,一次是恢复

三、并发锁优化

有3种方式可以降低锁的竞争程度:

  • 减少锁的持有时间
  • 降低锁的请求频率
  • 使用带有协调机制的独占锁,这些机制允许更高的并发性

3.1 减少锁持有时间

  • 缩小同步代码块范围
  • 拆分过大的同步代码块成小的同步代码块
  • 同步代码块不宜过小,需保证安全性、原子性
  • 同步代码块不易过多,避免频繁加锁解锁

3.2 降低锁粒度

  • 减少锁的请求频率,即请求锁数量少了,就能减少发生竞争的可能性

3.2.1 锁分解

  • 对象中存在多个相互独立的状态
  • 对象存在适中而不激烈的锁竞争
  • 根据相互独立的状态,使用不同的锁

3.2.2 锁分段

  • 锁分解的进一步扩展
  • 对象存在激烈的锁竞争
  • 根据不同的数据范围,使用不同的锁

3.2.3 避免热点域

  • 被多个锁共享的状态变量
  • 多个操作都涉及到的状态变量
  • 需要多个锁才能访问的状态变量
  • 避免热点域,因为它往往需要加多个锁,或者加全局锁才能操作

3.3 避免独占锁

  • 并发容器
  • 读写锁分离
  • 不可变对象
  • 原子变量
作者

jiaduo

发布于

2022-05-15

更新于

2023-04-03

许可协议