常见垃圾回收器 (Yong 年轻代,old 老年代,蓝色代表支持内存,红色代表STW时间:
Yong : Serial (串行)(m)、ParNew (G)、Parallel Scavenge (P开头并行)old :CMS ( concurrentMarkSweep ) (200ms)、Seraold 、Prallel old不区分: G1(逻辑分代)(分区region)(garbage first) (10ms)(百G)、ZGC (1ms) (4T - 2^24)、Shenandoah (4T)debug :EpSilonJDK版本对应
JDK 1.3.1 - 1.7 ,Serial + Serial old (新生代 + 老年代 + 永久代)JDK 1.8 , Parallel Scavenge + Prallel old (默认 ParallelGC)(新生代 + 老年代 + 元空间 metaspace ) 、G1 不区分,概念分代。JDK 1.9 ,CMS 以废弃.JDK 11 以后,ZGCJava 垃圾处理 (图片截图来自 --马士兵老师讲JVM)
垃圾: 没有任何引用指向的一个对象,或者一个循环引用对象定位垃圾:
引用计数 (reference count) - 问题:不能解决循环引用垃圾对象。 根搜索算法 (Root Searching)根对象: JVM stack (jvm栈里)、nataive method (本地方法栈)、run-time contant pool,(运行时常量池)、references in menthod area(静态引用)、Clazz,( load在内存的class对象)垃圾回收算法:
标记清除(Mark - Sweep): 标记:从根对象开始遍历,并对从跟对象可以访问到的对象打上一个标识 清除: 对堆内存从跟对象开始循环遍历,回收没有标记的对象 问题: 位置内存不连续,产生碎片 拷贝算法(copying): 内存一分为二,留一半把另一半存活对象复制过来。将内存划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的,当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。接下来GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。 问题: 浪费内存。 标记压缩 (Mark - Compcat): 可用对象移动覆盖垃圾对象,在进行压缩。堆内存逻辑分区:
分代 ↓新生代 :老年代 = 1:3 , eden :S0 :S1 = 8 :1:1第一次YGC (MinorGC),把存活对象拷贝进S0再次YGC,eden ,S0 存活对象拷贝进入S1再次YGC,eden . S1 存活对象拷贝进入S0存活年龄足够进入old区 (经历一次GC没被回收调 age +1)(CMS age:6 ,ParallelGC :15)老年代满了后触发一次FGC (Major GC)(YGC+ old gc) ,产生 STW (stop the wordl) 停顿现象 G1以后开始分区 (Copying 算法):优先清理垃圾最多的小块三色标记 (CMS): 定义: 当垃圾回收器去标记对象的时候,把对象逻辑上分成三种颜色。
白色:找到对象,还未识别是否是垃圾灰色: 识别对象不是垃圾,还未开始标记该对象成员变量指向黑色:识别对象不是垃圾,并且该成员变量继续标记完成了情况分析:
1 、浮动垃圾 (处理,下一轮GC清除) 2、漏标 :在运行中,灰色对象取消了对白色对象的引用,同时黑色对象指向了白色对象,然后黑色对象已近标记完成,白色对象就不会再被扫描,从而导致白色对象被回收,产生漏标导致内存泄漏。 cms解决方案,Incremental Update - 累加式更新: 把 A 处理成灰色,改变标志位。但是在并发标记时,还是会漏标:在并发标记时,线程一处理A时(变成灰色)线程二,又把A 标记完成标记为黑色,又变回去了。 G1解决方案(SATB - Snapsnot At the Begining): 当B指向D的消失的时候,把这个指针保存到GC的堆栈,下一轮扫描时看堆栈有没有被放入的指针,如果有拿出来在把对象D扫描一次看有没有对象指向D,如果有就不是垃圾。 ZGC解决方案: 颜色指针, 把剩余的4位用来做状态区分.java对象:
对象的创建过程:
new在内存申请一块空间,成员变量赋默认值 (0,空)(半初始化)调用构造方法赋值初始值建立关联,(引用指向)分代模型 -对象的分配:
当我们new一个对象时,首先在栈上分配 (在栈上分配的对象,不会牵扯GC,结束后直接弹出)当栈上分配不了时,根据对象的大小分配。大对象 → 进入 old 区,进过FGC后 被回收不是够大的对象,进入线程本地分配缓存区(Thread Local Alloction Buffer TLAB),在eden区为每一个线程分配一小块空间(解决线程竞争),后进入eden区在eden区经过一次GC后,如果被回收就结束,没有就进入 S0,在进行一次GC,被回收就结束,没有就继续,当 回收age满足条件后进入 old区,在FGC后被回收结束对象在内存上中的存储布局
注:一个对象默认是 16bytes,所在字节不能被 8 整除会 补齐 对象头主要包括: hashcode ,GC信息, 锁信息
public static void main(String[] args) throws InterruptedException { Student o = new Student(); o.setA(1); o.setB(1); o.setC(1); o.setD("1"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); } 8(markword)+4(classpointer)+12(int*3)+4(String)+4(padding)=32 bytes //默认开启,指针压缩,对象压缩(引用指向压缩) java -XX:+PrintCommandLineFlags -version -XX:InitialHeapSize=266183360 -XX:MaxHeapSize=4258933760 -XX:+PrintCommandLineFlags - XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC java version "1.8.0_221" Java(TM) SE Runtime Environment (build 1.8.0_221-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)对象定位
1.直接指针 : t → T (类型指针)→ 方法区 T.class ,直接指针速度快 ,在-GC回收时,会产生对象复制,t 指针会产生变化2.句柄池 : t -> 实例数据指针 | 类型数据指针 → 分别指向 , t 不会变化 , GC回收比较稳定volatile 作用:
1.线程可见性2.禁指重排 (防止指令重排序) public class VolatileTest { /** * 线程停止 * 有 volatile 修饰时,就会通知所有访问此变量的线程,重新load值到本地内存 */ private static volatile boolean volatileFlag=true; /** * 线程不停止 * 没有 volatile 修饰时,就一直访问的 线程本地内存,一直为true */ private static boolean flag=true; public static void main(String[] args) throws InterruptedException { new Thread(()->{ while (volatileFlag){ } System.out.println("end"); },"sever").start(); Thread.sleep(1000); volatileFlag=false; } } public class VolatileTest2 { private static int x=0,y=0; private static int a=0,b=0; /** * 正常情况执行顺序, * a=1 * x=b * b=1 * y=a * 不会出现 x=0,y=0;的情况 * 如果指令重排:↓ * x=b; 默认 b=0;a=0; * y = a; * b = 1; * a =1; * 就出现 x=0,y=0;的情况 * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { int i=0; for(;;){ i++; x=0;y=0; a=0;b=0; Thread one = new Thread(()-> { a=1; x=b; }); Thread other = new Thread(()-> { b = 1; y = a; }); one.start();other.start(); one.join();other.join(); String res="第"+i+"次(" + x + "," + y + ")"; if (x==0 && y==0){ System.out.println(res); break; } } } }JVM 调优
常见命令 nohup java -Xmx256m -Xms256m -Xmn128M -Xss256k -jar epay-check-account-0.0.4.jar -Xms<size> set initial Java heap size -Xmx<size> set maximum Java heap size top 、jpsarthas -阿里 jvm监测 在线文档:https://arthas.aliyun.com/doc/install-detail.html hlep 查询指令说明 ; thread -help, 具体命令用法说明
NAMEDESCRIPTIONdashboardOverview of target jvm’s thread, memory, gc, vm, tomcat infojvmDisplay the target JVM informationthreadDisplay thread info, thread stackredefineRedefine classes. @see Instrumentation#redefineClasses(ClassDefinition…)jvmDisplay the target JVM information
redefine : 重新编译,载入到内存。 (应急) redefine /root/TT.class
