java异常优化
1. Throwable 类中的重要方法
四个构造方法
- getMessage
- getLocalizedMessage
- printStackTrace
- getStackTrace
2. java 虚拟机栈
1. 栈
栈是限制插入和删除只能在一个位置上进行的线性表
2. 堆
堆是一种特别的树状数据结构,是一颗完全二叉树;但是,完全二叉树不一定是堆
3. 操作系统(java虚拟机)堆和栈
堆和栈是指对内存进行操作和管理的一些方式,注意要区分数据结构
4. 虚拟机栈的基本性质
-
内存管理
-
内容存放
-
结构
-
速度
-
申请大小限制
5. jvm 堆
- jvm里的“堆”特指用于存放java 对象的内存区域
- jvm堆被同一个jvm实例中的所有java线程共享
- jvm堆通常由某种内存管理机制所管理,这种机制叫做“垃圾回收”
6. 虚拟机堆栈异常
-
虚拟机栈可能会抛出两类异常
StackOverflowError OutofMemoryError
-
虚拟机堆可能会抛出异常
OutofMemoryError
7. 怎么处理异常
- 从源头减少异常
- 忽略不必要的异常
- 使用异常链定位异常
- 其他需要考虑细节
忽略不必要的异常
- 允许有一定的容错
- 网络、rpc出现错误可以重试
- 对业务本身不产生额外的影响
其他需要考虑的细节
- 不要大段使用try catch
- 不要捕获通用异常,应当具体化
- 及时的清理、释放资源
- 尽早地暴露异常
8. 如何记录日志
- 把工程中的异常信息记录到日志中,就可以通过查询日志定位问题
- 把业务流程信息记录到日志中,就可以知道程序的执行流是怎样的
- 通过日志查看、分析用户的操作,用于分析用户行为、审计等等功能
9. Log4j 进阶
-
LoggerContext
log的上下文环境,可以理解为他就是整个工程中log的所有
-
Configuration
每一个LoggeContext都有一个有效的Configuration,Configuration包含了所有的Appenders、上下文范围内的过滤器、LoggerConfigs等等
-
Logger
通过调用LogManager.getlogger方法获得,log客户端
-
LoggerConfig
每个LoggerConfig和Logger是对应的,获取到一个Logger,写日志时其实是通过LoggerConfig来记日志的
10. Logback基础与应用
-
配置方面
-
logback的应用
slf4j 对 jcl有所改进,支持占位符
支持打印不同级别的日志,但是只有 >= 设定级别的日志才会被记录下来
初始化会遵循一定的策略寻找配置文件
3. 日志记录
1. logback支持五种日志级别
trace debug info warn error
- 优先级逐渐增高
- 要注意工程中配置的优先级,因为会忽略掉低优先级的日志
- 要理解每一种优先级的设定含义(可以适配任意一种日志框架)
2. 合理的记录日志
- 搞清楚当前工程的日志级别,保证日志可以被打印
- 使用参数化形式{}占位,[] 进行参数隔离
- 日志的文件名称应该是可以自解释的,通常,至少会要求名称中包含类型标识和时间标志
- 日志要有滚动,这是考虑避免单个文件过大,以及磁盘占用问题
3. 让你的日志有意义(正确性)且不冗余(必要性)
- HTTP 请求的入参和结果
- 程序异常的原因
- 远程接口调用(HTTP 或 RPC )情况
- 特俗的条件分支
4. 哪些场景不应该打印日志
- 大数据量日志 浪费空间
- 在循环中打印日志,特别是大循环
- 没有意义的日志
- 如果日志什么都说明不了什么,那你一定要删除这条日志
- 密码、邮箱、手机号码属于私密信息,为了避免数据泄露,不应该打日志
5. 日志能够对业务逻辑进行解释
日志级别 日志内容 日志时间 线程名称 类方法名 一定需要的
行号 异常堆栈 可有可无
6. Logback的解析
-
MDC
Mapper Diagnostic Context , 可以粗略的理解成一个线程安全的存放诊断日志的容器
-
MDC 对外提供了哪些接口
PUT GET REMOVE CLEAR
7. MDC 用途
-
在web 应用中,如果想在日志中输出请求用户IP 地址、请求URL、统计耗时等等,MDC基本都能支撑
-
可以在MDC 中填充REQUEST_ID 追踪单个请求的执行轨迹
-
微服务场景下,使用MDC 埋点,做到链路跟踪
最好是有日志收集工具,将多实例、多系统的日志实现收集,在根据埋点进行grep,就可以打印一个完整的请求链路
8. 微服务环境下的日志链路
9. 好的日志应当是怎样的
-
有着合适的日志文件命名、滚动方式
-
在不同场景下选择了合适级别
-
选择好日志打印的实质,让你的日志有意义且不冗余
-
可读性高的日志内容与格式
4. 调试
1. 调试的概念
-
广义的调试
一切排查问题的方法都属于调试的范畴
-
狭义的调试
使用idea debug 、gdb、pdb专业调试工具的方式
2. 什么样的问题适合调试
- 适合调试的问题
方法参数传递的跟踪
变量在代码逻辑中的变化过程
不同(变量)条件下代码的执行轨迹、方式
- 不适合调试的问题
代码执行消耗过高的CPU(异常)
代码执行过程中出现了大量的线程
5. 线程堆栈
1. 含义
线程堆栈也称做线程调用堆栈。java线程堆栈是虚拟机中线程(包括锁)状态的一个瞬间快照,即系统在某个时刻所有线程的运行状态,包括每一个线程的调用堆栈,锁的持有情况等信息。
线程堆栈包含的信息:
- 线程的名字,ID ,线程的数量等等
- 线程的运行状态,锁的状态(锁被哪个线程持有,哪个线程在等待锁等等)
- 调用堆栈(即函数的调用层关系):包含完整的类名,所执行的方法,源代码的行数
2. 线程堆栈信息能用来解决什么问题
适合稳定性问题分析以及性能问题分析
- 系统在运行的过程中,突然CPU使用率过高
- 线程死锁、死循环、饥饿等
- 找出消耗CPU最高的线程
- 由于线程数量太多造成的系统失败(例如无法创建新的线程)
3. 线程的六种状态
-
源码路径
java.lang.Thread.State
-
一共六种
NEW RUNNING BLOCKED
WATING TIMED_WATING TERMINATED
4. 死锁的定义及形成过程
死锁是多线程特有的问题: 线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成
5. 死锁需要满足的四个条件
- 互斥条件 : 一个资源每次只能被一个线程使用
- 请求与保持条件 : 一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件 : 进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件 : 若干进程之间形成一种头尾相接的循环等待资源关系
6. 如何避免死锁
- 已固定的(正确的)顺序去获取锁
- 超时放弃,此时可以使用java.util.concurrent.locks.Lock tryLock(long time,TimeUnit unit)
6. jvm 调优
1. 什么是jvm 调优,调优的指标是什么
- jvm调优指的就是对当前系统进行性能调优,简单来说就是:尽可能使用较小的内存和CPU来让java程序获得更高的吞吐量及较低的延迟
- 调优都是由指标来支撑的
- 吞吐量 : 是指不考虑垃圾收集引起的停顿时间或内存消耗,应用达到的最高性能指标
- 延迟 : 缩短由于垃圾收集引起的停顿时间或者完全消除因垃圾收集引起的停顿,避免应用运行时发生抖动
- 内存占用: 垃圾收集器流畅运行所需要的内存数量
2. 何时需要考虑做jvm 调优呢
吞吐量低、延迟高、经常出现OOM
- Full GC 次数频繁
- GC 停顿时间过长
- 应用出现OutOfMemory等内存异常
- 系统吞吐量与响应性能不高或持续下降
3. jvm 调优的基本原则
- 大多数的java 应用不需要JVM 优化
- 大多数导致GC问题的原因是代码层面的问题导致的
- 减少使用全局变量和大对象;减少创建对象的数量
- 分析GC情况优化比优化JVM参数更好
- 优先架构调优和代码调优,JVM优化优先级放到最低