JVM

JVM

1、类加载器

  • Bootstrap(最底层)

    启动类加载器,C++编写

  • Extension

    扩展类加载器

  • AppClassLoader

    系统类加载器,加载当前应用的classpath的所有类

2、双亲委派机制和沙箱安全机制

  • 双亲委派

  • 沙箱安全

    防止恶意代码污染java源代码

3、Native关键字

  • Native Interface:本地接口

  • Native Method Stack:本地方法栈

4、PC寄存器

5、方法区
  • 供线程共享的内存区域,他存储了每一个类的结构信息,例如字段和方法数据,构造函数和普通方法的字节码内容。是一种规范,实现中最典型的就是永久代和元空间
  • 注意:实例变量 存在堆空间,和方法区无关

6、栈和堆

  • 栈管运行,堆管存储

  • 8种基本类型+对象的变量引用+实例方法都是存储在栈空间

  • 每个方法进入栈叫做栈针,栈针中保存3中类型的数据

    • 本地变量:入参、出参、方法内部的变量
    • 栈操作:记录入栈出栈的操作
    • 栈针数据:包括类文件、方法等
  • 栈+堆+方法区的交互关系

    HotSpot使用指针的方式来访问对象,java堆中会存放访问类元数据的地址,引用对象存储的直接就是对象的地址


  • 堆(逻辑上分下面三层,物理上只有上面两层)

    • 新生代(占堆空间的1/3)(Minor GC)

      • 伊甸园区(占新生代的8/10)

        new出来的实例对象存放在此处 ,对象过多是会触发轻GC进行回收,并不是清空,余下的进入下面的幸存者区

      • 幸存者0区(from区,占1/10)

      • 幸存者1区(to区,占1/10)

        • from区和to区位置 和名分不是固定的,每次GC之后会有交换,谁空谁是to区
    • 老年代(占堆空间的2/3)(Major GC也叫Full GC)

      满了之后开启重GC,如果老年代空间满了之后则报OOM(堆内存溢出)异常。堆内存可调

    • 元空间

      • 元空间并不在虚拟机中而是使用本机物理内存
    • 总结

  • 堆参数调优

    • -Xms(初始化大小)
      • 默认为物理内存的1/64
    • -Xmx(最大值)
      • 默认为物理内存的1/4
  • GC日志分析

  • GC是什么?

    • 次数上频繁收集Young区
    • 次数上较少收集Old区
    • 基本不动元空间
  • 普通GC与全局 GC的区别?

    普通GC只针对新生代区域的GC,…

  • 四大算法

    • 引用计数法

      JVM的实现基本上不使用这种方式,缺点:无法解决相互引用问题

    • 复制清除法

      用在年轻代,基本思想是:将内存分为两块,每次只用其中一块,当一块用完就将还活着的对象复制到另一块上面,优点是不会产生内存碎片,缺点是消耗空间

    • 标记清除

      用在老年代,算法分成两个阶段,先标记出要回收的对象,然后统一回收,优点:不需要额外的空间,缺点:两次扫描,耗时严重、会产生内存碎片

    • 标记压缩(标记-整理-清除)

      用在老年代,首先标记要清除的对象,再次扫描,并往一端移动扫描的对象,优点:没有内存碎片,缺点:移动对象需要成本

  • 小总结

    没有最好的算法,只有最合适的算法,即分代回收算法

    内存效率:复制>标记清除>标记整理

    内存整齐度:复制=标记整理>标记清除

    内存利用率:标记整理=标记清除>复制

7、JMM(java内存模型)

  • 三大特点

    • 可见性
    • 原子性
    • 有序性
  • volatile关键字的理解

    java虚拟机提供的轻量级的同步机制

  • 什么是JMM?

    1、JMM本身是一种抽象的概念并不存在,他描述的是一种规范,通过这种规范定义了程序中各个变量的访问方式 。

    2、由于JVM运行程序的实体是线程,而每个线程创建时都会为其创建一个工作内存(栈空间),工作内存是每个线程私有的数据区域,而java内存模型中规定所有的变量存储在主内存,主内存是共享区域,所有线程都可以访问,但是线程对变量的操作必须在自己的工作内存中进行,首先将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回内存,不能直接操作内存中的变量,各个线程的工作内存中存储的是主内存中变量的副本,因此不同的线程无法访问对方的工作内存,线程间的通信必须通过主内存来完成。