JVM -基础详细笔记整理

1 篇文章 0 订阅

JMM(Java Memory Model):

  • java内存模型定义了共享内存系统中,多线程程序读写操作行为规范,从而解决并发问题
    – eg: synchronized 、Lock 保证原子性
    – volatile 保证 可见性、有序性

JVM内存结构:

jmm

常见垃圾回收器 (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 :EpSilon
    在这里插入图片描述

JDK版本对应

  • 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 以后,ZGC

算法理解总结:

  • 最初:引用计数法,给每个对象分配一个引用计数器,引用指向一次+1,反之-1,为0则为垃圾,效率很低
  • 复制算法:新生代中把eden、from 区存活对象,复制到 to区(空)中,然后清除剩下垃圾
    –缺:浪费内存空间(因为需要一个空的内存区域)
    –优:不会存在内存碎片
    –场景:适用对象存活率低的时候,新生代
  • 标记清除:从根对象遍历查找标记活着的对象,然后清除没有任何引用指向的对象
    – 缺:两个扫描存在浪费时间、会产生内存碎片
    – 优:不要浪费额外空间
  • 标记清除压缩:对标记清除再优化,再次扫描存活的对象,移动至连续内存区域
    – 缺:3次扫描,以及对象移动成本
    – 优:内存连续,没有碎片
    – 场景:老年代

Java 垃圾处理 (图片截图来自 --马士兵老师讲JVM)

  • 垃圾: 没有任何引用指向的一个对象,或者一个循环引用对象
    java垃圾定义

定位垃圾:

  • 引用计数 (reference count) - 问题:不能解决循环引用垃圾对象。
    1
    2
    在这里插入图片描述
  • 根搜索算法 (Root Searching)
  • 根对象: JVM stack (jvm栈里)、nataive method (本地方法栈)、run-time contant pool,(运行时常量池)、references in menthod area(静态引用)、Clazz,( load在内存的class对象)
    1

垃圾回收算法:

  • 标记清除(Mark - Sweep)
    标记:从根对象开始遍历,并对从跟对象可以访问到的对象打上一个标识
    清除: 对堆内存从跟对象开始循环遍历,回收没有标记的对象
    问题: 位置内存不连续,产生碎片
    在这里插入图片描述
    拷贝算法(copying): 内存一分为二,留一半把另一半存活对象复制过来。
  • 将内存划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的,当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。接下来GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。
    问题: 浪费内存。copy
    标记压缩 (Mark - Compcat): 可用对象移动覆盖垃圾对象,在进行压缩。
    mark-compcat

堆内存逻辑分区:

  • 分代 ↓
  • 新生代 :老年代 = 1:2 , 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 算法)
  • 优先清理垃圾最多的小块region

三色标记 (CMS):
定义: 当垃圾回收器去标记对象的时候,把对象逻辑上分成三种颜色。

  • 白色:找到对象,还未识别是否是垃圾
  • 灰色: 识别对象不是垃圾,还未开始标记该对象成员变量指向
  • 黑色:识别对象不是垃圾,并且该成员变量继续标记完成了

情况分析:

  • 1 、浮动垃圾 (处理,下一轮GC清除)
    31
    2、漏标 :在运行中,灰色对象取消了对白色对象的引用,同时黑色对象指向了白色对象,然后黑色对象已近标记完成,白色对象就不会再被扫描,从而导致白色对象被回收,产生漏标导致内存泄漏。
    32
    cms解决方案,Incremental Update - 累加式更新: 把 A 处理成灰色,改变标志位。但是在并发标记时,还是会漏标:在并发标记时,线程一处理A时(变成灰色)线程二,又把A 标记完成标记为黑色,又变回去了。
    33
    G1解决方案(SATB - Snapsnot At the Begining):
    当B指向D的消失的时候,把这个指针保存到GC的堆栈,下一轮扫描时看堆栈有没有被放入的指针,如果有拿出来在把对象D扫描一次看有没有对象指向D,如果有就不是垃圾。
    g13
    ZGC解决方案: 颜色指针, 把剩余的4位用来做状态区分.
    z3

java对象:

对象的创建过程:

  • 检查类是否已经被加载
  • 为对象分配内存空间
  • 为对象的字段赋默认值;
  • 设置对象头;
  • 执行实例的初始化方法lint
  • 执行构造方法。
    oc

分代模型 -对象的分配:

  • 当我们new一个对象时,首先在上分配 (在栈上分配的对象,不会牵扯GC,结束后直接弹出)
  • 当栈上分配不了时,根据对象的大小分配。对象 → 进入 old 区,进过FGC后 被回收
  • 不是够大的对象,进入线程本地分配缓存区(Thread Local Alloction Buffer TLAB),在eden区为每一个线程分配一小块空间(解决线程竞争),后进入eden区
  • 在eden区经过一次GC后,如果被回收就结束,没有就进入 S0,在进行一次GC,被回收就结束,没有就继续,当 回收age满足条件后进入 old区,在FGC后被回收结束
    在这里插入图片描述

对象在内存上中的存储布局

o2
o1

注:一个对象默认是 16bytes,所在字节不能被 8 整除会 补齐
对象头主要包括: hashcodeGC信息锁信息

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());
}

o3

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.禁指重排 (防止指令重排序)
  • 3.不保证原子性
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;
            }
        }
    }

}

t1

JVM 调优

  • 常见命令
    nohup java -Xmx256m -Xms256m -Xmn128M -Xss256k -jar epay-check-account-0.0.4.jar
    -Xms<size> set initial Java heap size 默认物理内存 64/1
    -Xmx<size> set maximum Java heap size 默认物理内存 4/1
    -Xss 规定了每个线程堆栈的大小
    topjps
    jvisualvm.exe

arthas -阿里 jvm监测
在线文档https://arthas.aliyun.com/doc/install-detail.html
hlep 查询指令说明 ;
thread -help, 具体命令用法说明

1
a2

NAMEDESCRIPTION
dashboardOverview of target jvm’s thread, memory, gc, vm, tomcat info
jvmDisplay the target JVM information
threadDisplay thread info, thread stack
redefineRedefine classes. @see Instrumentation#redefineClasses(ClassDefinition…)
jvmDisplay the target JVM information

a3

redefine : 重新编译,载入到内存。 (应急)
redefine /root/TT.class

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值