JVM
一 jvm概述
1. 什么是jvm
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
2.概述
Java虚拟机有自己完善的硬件架构,如处理器、堆栈等,还具有相应的指令系统。
Java虚拟机本质上就是一个程序,当它在命令行上启动的时候,就开始执行保存在某字节码文件中的指令。Java语言的可移植性正是建立在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码文件(.class)就可以在该平台上运行。这就是“一次编译,多次运行”。
Java虚拟机不仅是一种跨平台的软件,而且是一种新的网络计算平台。该平台包括许多相关的技术,如符合开放接口标准的各种API、优化技术等。Java技术使同一种应用可以运行在不同的平台上。Java平台可分为两部分,即Java虚拟机(Java virtual machine,JVM)和Java API类库。 [1]
3.体系结构概览
二 类装载器
1. 虚拟机自带三个
(1) 启动类加载器(bootstrap) C++
(2) 扩展类加载器(extension) java
(3) 应用程序类加载器(appClassLoader),也叫系统类加载器,加载当前应用的classpath的所有类
2.用户可以实现Classloader 自定义加载器(一般不用)
双亲委派机制:使用类A.class时,从顶级父类一层一层往下找,找到了使用,未找到报空指针异常。(java程序有健壮性)
沙箱安全机制
三 本地接口
为了融合不同的编程语言为java所用(可以使用java调用其他不同语言的方法)
在本地方法栈中登记 native方法,在 execution engine执行时加载本地方法库
四 PC寄存器(程序计数器)
线程私有
内存占据很小,可以忽略不计
用于记录程序执行的指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址)
如果执行一个native方法,则这个计数器是空的
五 方法区
线程共享
JDK版本相关,1.7以前为永久代,1.8后是元空间
存储每一个类的结构信息,例如运行时的常量池,字段,和方法数据,构造函数和普通方法。以及static方法和属性。
六 栈区
线程私有,生命周期跟随线程的生命周期。8中基本类型变量+对象引用变量+实例方法都是在函数的栈内存中分配
不参与垃圾回收
主要存储3类数据:
(1) 本地变量:输入参数和输出参数以及方法内的变量
(2) 栈操作:记录入栈,出栈的操作
(3) 栈帧数据:包括类文件,方法等等
栈运行原理
(1) 先进后出
(2) 每个方法在运行的时候都会创建一个栈帧,用于存储局部变量,操作数栈,动态链接,方法出口等信息
七 对象生命周期
堆内存分配
对象生成后,进入eden区,当eden满了之后,发生一次GC(YGC),清空全部eden区,如果eden区的对象还存在引用,则放入S0区(幸存区from),如果S0和S1中的对象不存在引用,则一起回收掉,如果依然存在引用,则保留,将其生命周期+1(一般到15会进入老年代区)
当老年代区占满后,会发生一次Full GC ,清除掉老年代区中没有被引用到的对象,full gc时间会更长。(一般优化的原则是尽量保证程序不进行full gc)
当老年代区的对象占满,新生代区持续向老年代区存放对象时,会发生内存溢出。
八 JVM参数调整
JVM虚拟机大小
最大值Xmx,默认为当前运行物理机的内存1/4
最小值Xms, 默认为当前运行物理机内存的1/64
实际生产中, Xmx和Xms设置成一样,避免内存忽高忽低,造成卡顿。
输出gc日志参数 -XX:+PrintGCDetails
调整最大内存和最小内存 -Xmx1024m -Xms1024m
多个配置之间使用空格隔开
九 垃圾回收四大算法
1.引用计数法:基本不用
**实现**:当一个对象存在引用的时候,就在该对象的引用计数上加1,当不存在引用的时候,为0,代表可以回收。
**缺陷**:
每次对对象赋值都要维护引用计数器,且计数器本身也有一定的消耗
较难处理循环引用
2.复制算法(YGC使用)
一般发生在年轻代区。
当年轻代区发生GC时,会全盘扫码eden区和S0(from)区,当eden区的对象没有被引用时,则清除,有引用的,则放入S0区,如果S0区的对象依然被引用,则将被引用的对象放入S1(区),如果S1区已满,则将S1区的对象全部放入老年代区。最后,S1区的对象会全部复制到S0区,此时S1(to)区为空,S0区是当前GC后的全部存活对象。(印证谁空谁是to区)
**缺点**:耗费空间
3.标记清除算法
分为两个阶段,第一阶段标记出要回收的对象,第二阶段进行统一回收
缺点:两次扫描,耗时严重。会产生内存碎片
4.标记压缩(老年代区使用,和标记清除算法混合使用)
一般和标记清除算法一起使用,先标记,再整理,最后清除
缺点:耗时,需要整理移动所有存在引用的对象
总结
内存效率: 复制算法>标记清除算法>标记整理算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
内存整齐度: 复制算法=标记整理算法>标记清除算法。 内存利用率: 标记整理算法=标记清除算法>复制算法。 可以看出,效率上来说,复制算法是当之无愧的老大,但是却浪费了太多内存,而为了尽量兼顾上面所提到的三个指标,标记/整理算法相对来说更平滑一些,但效率上依然不尽如人意,它比复制算法多了一个标记的阶段,又比标记/清除多了一个整理内存的过程
十 JVM相关问题:
1. JVM内存模型以及分区,需要详细到每个区放什么?
2. 堆里面的分区:Eden,survival from to,老年代,各自的特点?
3. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方?
4. Minor Gc 与Full GC分别在什么时候发生?
- 本文标签: Java
- 本文链接: https://www.tianyajuanke.top/article/26
- 版权声明: 本文由吴沛芙原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权