腾讯云主机做网站,昆明seo博客南网站建设,wordpress 如何用pdf,dedecms企业网站1.JVM是什么
JVM#xff08; Java Virtual Machine#xff09;就是Java虚拟机。 Java的程序都运行在JVM中。 2.JVM的运行流程
JVM的执行流程#xff1a; 程序在执行之前先要把java代码转换成字节码#xff08;class文件#xff09;#xff0c;JVM 首先需要把字节码通过…1.JVM是什么
JVM Java Virtual Machine就是Java虚拟机。 Java的程序都运行在JVM中。 2.JVM的运行流程
JVM的执行流程 程序在执行之前先要把java代码转换成字节码class文件JVM 首先需要把字节码通过一定的方式类加载器ClassLoader 把文件加载到内存中运行时数据区Runtime Data Area 而字节码文件是 JVM 的一套指令集规范并不能直接交个底层操作系统去执行因此需要特定的命令解析器执行引擎将字节码翻译成底层系统指令再交由CPU去执行而这个过程中需要调用其他语言的接口 本地库接口Native Interface 来实现整个程序的功能这就是这4个主要组成部分的职责与功能。
2.1类加载子系统
对于一个类来说它的生命周期是这样的 所以对于类加载来说总共分为以下几个步骤
加载连接 ①验证 ②准备 ③解析初始化
1.连接
在加载 Loading 阶段Java虚拟机需要完成以下三件事情 1通过一个类的全限定名来获取定义此类的二进制字节流。 2将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。 3在内存中生成一个代表这个类的java.lang.Class对象作为方法区这个类的各种数据的访问入口。 总结读取.class文件 2.连接
①验证
验证.class是否符合JVM的规范。
验证选项
文件格式验证字节码验证符号引用验证…
②准备
准备阶段是正式为类中定义的变量即静态变量被static修饰的变量分配内存并设置类变量初始值的阶段。
比如此时有这样一行代码
public static int value 123;它是初始化 value 的 int 值为 0而非 123。
③解析
解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程也就是初始化常量的过程。
3.初始化
初始化阶段Java 虚拟机真正开始执行类中编写的 Java 程序代码将主导权移交给应用程序。初始化阶段就是执行类构造器方法的过程。
4.双亲委派模型
如果一个类加载器收到了类加载的请求它首先不会自己去尝试加载这个类而是把这个请求委派给父类加载器去完成每一个层次的类加载器都是如此因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中只有当父加载器反馈自己无法完成这个加载请求它的搜索范围中没有找到所需的类时子加载器才会尝试自己去完成加载。 如上图所示
BootStrap 启动类加载器加载 JDK 中 lib 目录中 Java 的核心类库即$JAVA_HOME/lib目录。ExtClassLoader扩展类加载器。加载 lib/ext 目录下的类。AppClassLoader应用程序类加载器加载我们写的应用程序。自定义类加载器根据自己的需求定制类加载器。 new一个我们自己创建的类时先向上加载到扩展类如果没有找到这个类再向上加载询问启动类是否有如果没有再向下加载一直到我们写的应用程序。
避免了恶意代码去修改JDK的风险。
2.2运行时数据区
JVM 运行时数据区域也叫内存布局但需要注意的是它和 Java 内存模型(Java Memory Model简称JMM完全不同属于完全不同的两个概念)
1.方法区
存放的是类对象可以理解为对象的模板。(存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据) 在《Java虚拟机规范中》把此区域称之为“方法区”而在 HotSpot 虚拟机的实现中在 JDK 7时此区域叫做永久代PermGenJDK 8 中叫做元空间Metaspace。 2.堆
存放的是new出来的对象。真正的对象的地址。
3.JVM虚拟机栈
每一个线程都有对应一个Java虚拟机栈每调用一个方法都会以栈帧的形式加入到线程的栈中每个方法在执行的同时都会创建一个栈帧Stack Frame用于存储局部变量表、操作数栈、动态链接、方法出口等信息方法执行完成之后栈帧就会被调出栈。栈主要记录的是方法的调用关系还有可能会出现的栈溢出的错误。 4.本地方法栈
本地方法栈和虚拟机栈类似只不过 Java 虚拟机栈是给 JVM 使用的而本地方法栈是给本地方法使用的。
5.程序计数器
记录当前线程的方法执行到哪一行。
3.垃圾回收
当方法结束或者线程结束时内存就会跟着线程被回收。这种就称之为垃圾回收。 java堆中存放着几乎所有的对象实例垃圾回收器在对堆进行垃圾回收前首先要判断这些对象哪些还存活哪些已经死去。判断对象是否已死有如下几种算法。
3.1垃圾回收的过程 新生代一般创建的对象都会进入新生代的Eden中老年代大对象和经历了 N 次一般情况默认是 15 次垃圾回收依然存活下来的对象会从新生代 移动到老年代。老年代的大小时新生代的两倍。
垃圾回收的过程如下
首先创建对象进入Eden中 当Eden满了之后下图将还活着的对象移入S0中剩余的都是“死去“的对象打红叉的对象为已死的对象清空所有死去对象垃圾回收。再次创建新的对象。 当Eden又满了之后下图将还活着的对象移入S1中清空所有”死去的对象“。再次创建新的对象。 交换S1和S0. 当Eden又满了之后下图将还活着的对象移入S0中清空所有”死去的对象“。交换S1和S0. 重复上述过程。存活了15轮的对象会被放入老年区当老年区满了之后会进行一次老年区的垃圾回收。
3.2死亡对象的判断算法JVM采用
1.引用计数算法
给对象增加一个引用计数器每当有一个地方引用它时计数器就1当引用失效时计数器就-1任 何时刻计数器为0的对象就是不能再被使用的即对象已死。
但是在主流的JVM中没有选用引用计数法来管理内存最主要的原因就是引用计数法无法解决对象的 循环引用问题。
示例
public class Test {public Object instance null;private static int _1MB 1024 * 1024;private byte[] bigSize new byte[2 * _1MB];public static void testGC() {Test test1 new Test(); //第1行Test test2 new Test(); //第2行test1.instance test2; //第3行test2.instance test1; //第4行test1 null; //第5行test2 null; //第6行// 强制jvm进行垃圾回收System.gc();}public static void main(String[] args) {testGC();}
}在这个代码中编号按照代码中注释给出第12行分别调用了GCDemo01一次那么在堆上它们的计数器分别1。第34行又分别再次调用了GCDemo01一次那么在堆上它们的计数器都变为2.。但在第56行中计算器虽然分别都减一但test1和test2的instance再也无法访问到所以堆中的引用计数器无法归0导致垃圾无法被回收。
2.可达性分析算法
通过一系列称为GC Roots的对象作为起始点从这些节点开始向下搜索搜索走过的路径称之为引用链当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时证明此对象是不可用的。以下图为例
有引用关系的就会被标记为灰色。 对象Object5-Object7之间虽然彼此还有关联但是它们到GC Roots是不可达的因此他们会被判定为可回收对象。
在Java语言中可作为GC Roots的对象包含下面几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象方法区中类静态属性引用的对象方法区中常量引用的对象本地方法栈中 JNI(Native方法)引用的对象
3.3垃圾回收算法
通过上面的算法我们可以将死亡对象标记出来了标记出来之后我们就可以进行垃圾回收操作了在正式学习垃圾收集器之前我们先看下垃圾回收机器使用的几种算法这些算法是垃圾收集器的指导思想。
1.标记-清除算法
标记-清除算法是最基础的收集算法。算法分为标记和清除两个阶段 : 首先标记出所有需要回收的对象在标记完成后统一回收所有被标记的对象。后续的收集算法都是基于这种思路并对其不足加以改进而已。
标记-清除算法的不足主要有两个 :
效率问题 : 标记和清除这两个过程的效率都不高空间问题 : 标记清除后会产生大量不连续的内存碎片空间碎片太多可能会导致以后在程序运行中需要分配较大对象时无法找到足够连续内存而不得不提前触发另一次垃圾收集。 2.复制算法新生代使用
复制算法是为了解决标记-清理的效率问题。它将可用内存按容量划分为大小相等的两块每次只使用其中的一块。当这块内存需要进行垃圾回收时会将此区域还存活着的对象复制到另一块上面然后再把已经使用过的内存区域一次清理掉。这样做的好处是每次都是对整个半区进行内存回收内存分配时也就不需要考虑内存碎片等复杂情况只需要移动堆顶指针按顺序分配即可。此算法实现简单运行高效。算法的执行流程如下图 :
3.标记-整理算法老年代使用
复制收集算法在对象存活率较高时会进行比较多的复制操作效率会变低。因此在老年代一般不能使用复制算法。
针对老年代的特点提出了一种称之为标记-整理算法。标记过程仍与标记-清除过程一致但后续步骤不是直接对可回收对象进行清理而是让所有存活对象都向一端移动然后直接清理掉端边界以外的内存。流程图如下: 优点在回收过后多了一步整理内存的工作 缺点可以有大量连续的内存空间 3.4垃圾收集器7种
如果说收集算法是内存回收的方法论那么垃圾收集器就是内存回收的具体实现。
垃圾收集器的作用垃圾收集器是为了保证程序能够正常、持久运行的一种技术它是将程序中不用的死亡对象也就是垃圾对象进行清除从而保证了新对象能够正常申请到内存空间。
垃圾收集器不断更新的目的减少STW的时间Stop The WorldSTW每次进行垃圾回收的时候程序会进入暂停状态
以下这些收集器是 HotSpot 虚拟机随着不同版本推出的重要的垃圾收集器
上图展示了7种作用于不同分代的收集器如果两个收集器之间存在连线就说明他们之间可以搭配使用。
Serial收集器Serial 收集器是最基本、发展历史最悠久的收集器这个收集器是一个单线程的收集器是虚拟机运行在Client模式下的默认新生代收集器与其他收集器的单线程比简单而高效。与Serial Old配对使用。ParNew收集器其实就是Serial收集器的多线程版本。对于Serial的优化从串行变成并行用多线程的方式扫描内存提高垃圾回收的效率减少STW的时间。Parallel Scavenge收集器(新生代收集器,并行GC) Parallel Scavenge收集器是一个新生代收集器它也是使用复制算法的收集器又是并行的多线程收集器。与Parallel Old配对使用。CMS收集器老年代收集器并发GC使用的是三色标记算法。G1收集器(唯一一款全区域的垃圾回收器)G1收集器不分老年代和新生代。
补充
1.Minor GC和Full GC的区别
面试题 : 请问了解Minor GC和Full GC么这两种GC有什么不一样吗
Minor GC又称为新生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特性因此Minor GC(采用复制算法)非常频繁一般回收速度也比较快。Full GC 又称为老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了Major GC经常会伴随至少一次的Minor GC(并非绝对在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。
2.4个引用