::: tip volatile
两个核心特性
- 保证变量对所有线程的可见性。
可见性是指:当一条线程修改了这个变量的值,新值对其他线程来说是可以立即得知的。 - 禁止指令重排序
:::
::: tip JVM GC类型
- Minor GC:针对新生代的GC,通常使用
标记-清除或标记-复制 - Old GC:针对老年代GC,为了长久的性能考虑,通常使用
标记整理,CMS会使用标记-清除,但是当清除后空间还是不够时,会触发一次标记-整理的Full GC,此时会加大单次GC的时间长度 - Full GC:针对全堆GC,会单独触发Minor GC与Old GC,具体什么算法看垃圾收集器
- Mix GC:混合着新生代与老年代的GC,G1专有
:::
::: tip JVM GC 算法
-
根节点枚举
- 三色标记
- 初始状态所有对象为白色,根节点枚举的是黑色,根节点直接引用的会变为黑色,如果还有未标记的引用,则为灰色,最终为白色的全部进行回收
- 回收线程与用户线程同时进行时,会出现对象被迁移的情况:新增黑色对象对白色对象的引用,删除了全部从灰色对象对白色对象的直接或间接引用
- 增量更新 - 解决黑色新增白色节点,会以黑色对象为根,按照新增的链路进行标记
- 原始快照 - 解决灰色失去白色节点,会以灰色对象为根,按照原始的链路进行标记
- 回收算法
- 分代收集理论
- 强分代假说和弱分代假说:大多数对象朝生夕灭,熬过越多次垃圾回收的对象越难回收。所以分为新生代和老年代
- Minor GC - 针对新生代的GC
- Major GC - 针对老年代的GC
- Full GC - 针对全堆的GC
- 标记 - 清除
- 速度快,但是会出现内存碎片,导致内存泄露
- 标记 - 复制
- 速度中,不会出现因内存碎片出现的内存泄露,但是会增加内存消耗(新增了Eden区,整个新生代分为一个Survivor和两个Eden区,比例为8:1:1)
- 标记 - 整理
- 速度慢,但是内存利用率很高
:::
- 速度慢,但是内存利用率很高
- 分代收集理论
::: tip Full GC的触发场景
- 手动调用System.gc(),但是具体什么时候调用还得看垃圾收集器的
- Eden区进行老年代晋升时内存不够,触发
内存担保,而老年代空间本身也不够时,进行Full GC - CMS进行Old GC后发现空间还是不够时进行Full GC
:::
::: tip 有哪些类加载器
- 启动类加载器:BootstrapClassLoadler
- 扩展类加载器:ExtClassLoader
- 应用程序类加载器:
:::
::: tip JVM 双亲委派
什么是双亲委派
类由类加载器进行加载,双亲委派会将类加载器分层,当类加载器收到一个加载类的请求时,会将类加载的请求委托给父加载器处理。每层类加载器都会判断当前类是否已加载,是否可以加载。当父加载器无法处理时,才在本地进行的类加载。
双亲委派有什么优点
- 避免重复加载类
- 避免核心类被篡改
- 解决了各个加载器中基础类统一的问题
:::
::: tip 什么时候需要破坏双亲委派
主要场景
在于JDK需要调用三方库时需要破坏,因为双亲委派并不能使用子加载器进行类加载,而JDK位于启动类加载器(顶层),三方库位于系统类加载器(classPath下),此时JDK调用三方库中类时,如果无法绕开双亲委派,就会出现无法加载类的错误。
具体实现
JDK提供了SPI(服务提供者接口),允许第三方厂家提供接口的实现类,此时SPI位于JDK的启动类加载器,三方实现类位于系统类加载器。
使用线程上下文类加载器(TCCL:Thread Context ClassLoader)可以在Thread中调用setContentClassLoad,getContentClassLoad来控制线程上下文类加载器,如果不设置,默认获取父类的线程上下文类加载器,初始的默认应用上下文类加载器是ApplicationClassLoader。
实际情况
程序运行中,即可通过Thread.currentThread().getContextClassLoad()获取当前线程的上下文类加载器来加载三方类。
:::
::: tip 常见的JVM调优方法有哪些
- console
- jProfile
- VisualVM
- Dump线程详细信息:查看线程内部运行情况
- jmap -heap pid :查看堆栈使用信息,Xmx调整为老年代使用大小的3倍
:::
::: tip Spring Bean 生命周期
{{{width="auto" height="auto"}}}
:::
::: tip JVM 调优 - jps
使用场景:查看有哪些Java进程、启动参数的信息
jps //查看当前用户的Java进程
jps -q //仅输出VM标识符,PID
jps -l //输出jar包完整的存放路径或者完整的包名
jps -m //输出传递给main方法的参数
jps -v //输入当前用户下的Java进程的启动参数
jps -V //效果同jps
:::
::: tip JVM 调优 - jstat
使用场景:查看GC信息,可以用做监控信息,侧重GC的次数与结果
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
jstat -gc pid //查询一次进程 pid 的垃圾收集情况
jstat -gc pid 250 20 //查询进程 pid 的垃圾收集情况,每250毫秒查询一次,一共查询20次。
jstat -gccause pid //额外输出上次GC原因
jstat -calss pid //类装载、类卸载、总空间以及所消耗的时间
jstat –gcnew pid //监视新生代GC的状况
jstat –gcold pid //监视老年代GC的状况
:::
::: tip JVM 调优 - jmap
使用场景:查看堆的使用情况,侧重当前的使用情况
jmap -heap pid //查看java 堆(heap)使用情况和堆内存的初始化值(易读,清晰)
jmap -histo pid //查看堆内存(histogram)中的对象数量及大小 (实用)
jmap -histo:live pid //JVM会先触发gc,然后再统计信息 (gc后对象一下少了一半)
jmap -dump:format=b,file=heapDump pid //将内存使用的详细情况输出到文件,之后一般使用其他工具进行分析。
:::
::: tip JVM 调优 - jstack
使用场景:查看进程的线程使用情况
jstack pid //查看线程情况
jstack -F pid //正常输出不被响应时,使用该指令
jstack -l pid //除堆栈外,显示关于锁的附件信息
参考文章:Java——命令jps、jstat、jmap、jstack、jhat、jinfo
:::
::: tip JVM常见问题
频繁GC问题或内存溢出问题
一、使用jps查看线程ID
二、使用jstat -gc 3331 250 20 查看gc情况,一般比较关注PERM区的情况,查看GC的增长情况。
三、使用jstat -gccause额外输出上次GC原因
四、使用jmap -dump:format=b,file=heapDump 3331生成堆转储文件
五、使用jhat或者可视化工具(Eclipse Memory Analyzer 、IBM HeapAnalyzer)分析堆情况。
六、结合代码解决内存溢出或泄露问题。
死锁问题
一、使用jps查看线程ID
二、使用jstack pid查看线程情况
OutOfMemery如何处理
首先线上应用的jvm配置要养成良好的习惯,增加一下配置则可以在jvm发生 oom的时候自动dump日志了 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/log/dump/jvm-oom.log
总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
:::
::: tip JVM 加载
- 加载 - 加载二进制字节码,将字节码对应的数据结构加载到方法区/元空间
- 验证 - 验证字节码是否符合jvm的要求,有点像判断是否能编译通过
- 准备 - 为静态变量分配内存空间,设置为零值,实例变量在new时分配空间
- 解析 - 将字节码中的符号运用(比如:引用Date类)解析成运行时的内存中的地址引用
- 初始化 - 将类的静态变量,由默认零值变为自定义的初始值
- 使用 - 执行静态代码块、自己编写的new之类的业务代码
- 卸载 - 类卸载,可以进行垃圾回收,但是这部分的垃圾回收通常效果都不好,因为卸载的要求比较苛刻,需要类没有任何地方使用,回收后的效果也不是很明显,通常不研究,而且在1.8后,将类的加载放在了元空间里,主要受机器内存大小的限制
:::
::: tip 引用 - 强、软、弱、虚
- 强引用 - 普通new出来的变量,只有在退出方法后,触发GC时才能回收
- 软引用 - 描述一些有用但非必须的对象,继承于SoftReference,在将要出现内存溢出之前进行回收,通常可用来做缓存
- 弱引用 - 比软引用更弱,描述一些非必须的对象,继承于WeakReference,当垃圾收集器开始工作时,无论内存是否充足,都会被回收
- 虚引用 - 最弱的一种引用关系,继承于PhantomReference,唯一用处在于对某个对象被回收时能做一个通知
:::
::: tip List 和 Map 区别
在此输入内容
:::