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
- -Xms(初始化大小)
-
GC日志分析
-
GC是什么?
- 次数上频繁收集Young区
- 次数上较少收集Old区
- 基本不动元空间
-
普通GC与全局 GC的区别?
普通GC只针对新生代区域的GC,…
-
四大算法
-
引用计数法
JVM的实现基本上不使用这种方式,缺点:无法解决相互引用问题
-
复制清除法
用在年轻代,基本思想是:将内存分为两块,每次只用其中一块,当一块用完就将还活着的对象复制到另一块上面,优点是不会产生内存碎片,缺点是消耗空间
-
标记清除
用在老年代,算法分成两个阶段,先标记出要回收的对象,然后统一回收,优点:不需要额外的空间,缺点:两次扫描,耗时严重、会产生内存碎片
-
标记压缩(标记-整理-清除)
用在老年代,首先标记要清除的对象,再次扫描,并往一端移动扫描的对象,优点:没有内存碎片,缺点:移动对象需要成本
-
-
小总结
没有最好的算法,只有最合适的算法,即分代回收算法
内存效率:复制>标记清除>标记整理
内存整齐度:复制=标记整理>标记清除
内存利用率:标记整理=标记清除>复制
7、JMM(java内存模型)
-
三大特点
- 可见性
- 原子性
- 有序性
-
volatile关键字的理解
java虚拟机提供的轻量级的同步机制
-
什么是JMM?
1、JMM本身是一种抽象的概念并不存在,他描述的是一种规范,通过这种规范定义了程序中各个变量的访问方式 。
2、由于JVM运行程序的实体是线程,而每个线程创建时都会为其创建一个工作内存(栈空间),工作内存是每个线程私有的数据区域,而java内存模型中规定所有的变量存储在主内存,主内存是共享区域,所有线程都可以访问,但是线程对变量的操作必须在自己的工作内存中进行,首先将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回内存,不能直接操作内存中的变量,各个线程的工作内存中存储的是主内存中变量的副本,因此不同的线程无法访问对方的工作内存,线程间的通信必须通过主内存来完成。