1.什么是垃圾
垃圾:没有引用指向的一个对象或者多个对象循环引用但是没有引用指向
申请内存方式
c语言:malloc free
c++:new delete
java:new 对象
2、垃圾是如何产生的
垃圾一般在发生引用传递时产生。一块堆内存可以被不同的栈内存所引用,每一块栈内存都会表示一个堆内存的地址
信息,并且一块栈内存只能保存一个堆内存的地址信息,所以当一块栈内存已经保存了一个堆内存的地址信息,
这个时候如果想要改变这个栈内存的引用指向时,就必须抛弃原来保存的地址信息,再保存新的堆内存的地址信息,
而这个时候就发生了引用传递。
3、垃圾定位算法
1.引用计数
2.根可达算法:由根对象引用开始自顶向下寻找,找不到的对象就是垃圾对象
4、垃圾回收算法
Mark_Sweep(标记清除)
绿色代表没有使用,灰色代表正在使用,黑色代表垃圾部分,标记清除就是找出垃圾把其标记为非垃圾区域
缺点:位置不连续 产生碎片
Copying(拷贝)
缺点:没有碎片,浪费空间(内存的拷贝速度是非常快的)
Mark-Compact(标记压缩)
缺点:没有碎片,效率偏低(与copy一样需要进行对象地址的挪动,这就涉及到线程同步,线程同步的开销就非常大)
5、jvm内存分代模型
1.部分垃圾回收器使用模型
2.新生代+老年代+永久代(1.7以前)/元数据区(1.8 Metaspace)
永久代与元数据区的比较
永久代必须指定大小限制,所以后面当内存满了就会成为性能的上限
元数据可以设置也可以不设置,无上限(受限于物理内存)
字符串常量1.7-永久代 1.8-放在堆中
MethodArea逻辑概念-永久代、元数据
3.新生代=Eden+2个suvivor区
YGC回收后,eden区中大多数对象会被回收,活着的进入s0
再次YGC,eden+s0中活着的对象进入s1;
再次YGC,eden+s1中活着的对象进入s0(s0 与s1不断交换)
出现以下两种情况会进入老年代
年龄足够—>老年代
s区装不下–>老年代
问题一:为什么eden:s0:s1=8:1:1 :
答:eden中90%的对象会被回收,10%进入s区中
问题二:为什么有两个s区:
答:为了提高GC的效率,分开管理刚new出来的对象,当前没有被YGC清理的对象以及需要进入老年代的对象
4、老年代存储顽固分子,老年代满了 进行FGC(full gc)
5.GC Tuning(gc调优)
1、尽量减少FGC
2、minorGC = YGC
3、MajorGC = FGC
6、常见的垃圾回收器
1.Serial年轻代 单线程串行回收
2.PS年轻代 多个线程并行回收
3.ParNew 年轻代 配合CMS的并行回收
4.SerialOld Serial回收算法放在老年代
5.ParallOld PS并行回收算法放在老年代
6.ConcurrentMarkSweep 老年代 并发的,垃圾回收和应用程序同时运行,降低STW(Stop the word 垃圾回收停顿时间)的时间(200ms左右)
7.G1(garbage first garbage collector)(10ms)
8.ZGC(1ms) PK c++
9.Shenandoah
10.Eplison
大多数gc调优是1,2,4,5,原因:1.8默认垃圾回收器 PS+ParalleOld
7、JVM调优第一步,了解生产环境下的垃圾回收器组合
jvm的命令参数参考: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
jvm的命令类
标准命令:-开头,所有的HotSpot都支持
非标准命令:-X开头,特定版本HotSpot支持特定命令
不稳定命令:-XX开头,下个版本可能取消
-XX:+PrintCommandLineFlags 查询项目中有哪些参数
-XX:+PrintFlagsFinal最终参数值
-XX:+PrintFlagsInitial 默认参数值
8.从线程角度理解垃圾回收
CMS回收的四个过程:初始标记、并发标记、重新标记、并发清理
(蓝色箭头代表程序或者程序的进程线程,黄色代表垃圾回收线程,两条竖线之间表示STW)
初始对象:标记root对象产生的对象,(遍历后找不到的为垃圾对象)
并发标记:找到根上能够联系到的对象,并开始快速标记,可能会漏标,可能会有一个新的引用指向以前垃圾对象(变为不是垃圾)
重新标记:都STW,然后对漏标和变化后的对象进行标记
并发清理:开始垃圾回收,这个过程可能会产生新的垃圾成为浮动垃圾floating garbage,这些垃圾下次继续重复上面四个过程