一、概述
1、简要了解java的技术体系
- Java程序设计语言
- JVM
- Clas文件格式
- JavaApi类库
2、Java的运行机制
java运行机制.pngJava编写的程序通过Java编译器编译成Java字节码(class文件),Java虚拟机载入字节码, 解释运行程序。
3、什么是Java虚拟机
Java虚拟机(Java Virtual Machine 简称JVM) 是运行所有Java程序的抽象计算机,是Java语言的运行环境。
Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
二、JVM结构
JVM结构图.png1、类加载器(ClassLoader)
类的装载.png是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
(1) 装载:查找和导入Class文件;
(2) 链接:把类的二进制数据合并到JRE中;
- 校验:检查载入Class文件数据的正确性;
- 准备:给类的静态变量分配存储空间;
- 解析:将符号引用转成直接引用;
(3) 初始化:对类的静态变量,静态代码块执行初始化操作
(4) 使用: 类的使用
(5) 卸载: 生命周期结束
2、执行引擎
负责执行class文件中包含的字节码指令
3、本地方法接口
主要是调用C或C++实现的本地方法及返回结果
4、运行时数据区
运行时数据区.png方法区
- 用于存放已被虚拟机加载的类信息、常量、静态变量、编译后的代码等数据。
- 各个线程共享的存储区域
- 熟悉HotSpot虚拟机的开发人员称之为"永久代",本质上两者并不相等
- 虽然JVM规范把方法区描述为堆的一个逻辑部分, 但它却有个别名non-heap(非堆),目的在于与Heap区分开来
堆
- 用于存放对象实例,几乎所有对象实例都在这里分配内存
- JVM中内存最大的一块
- 所有线程共享的内存区域
- 垃圾收集器管理的主要区域
- 可细分为新生代和老年代
虚拟机栈
- 每运行一个方法就创建一个栈帧,用于存储局部变量表、操作栈、方法返回值等。
- java栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的java栈
- 线程私有, 生命周期与线程相同
- 每一个方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程
本地方法栈
- 与虚拟机栈作用相似, 区别在于本地方法栈使用到的是Native方法服务
程序计数器
- 是一块较小的内存空间,作用是当前线程所执行的字节码的行号指示器
- 字节码解释器工作时通过改变计数器的值选取下条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能所需要依赖计数器完成
- 为避免线程间计数器的互相影响,每个线程都需要有一个独立的程序计数器
三、垃圾回收(GC)
垃圾回收主要有两个步骤:
- 垃圾判断: 检索哪些对象是可回收的垃圾
- 垃圾回收: 对检测出的垃圾进行销毁回收, 腾出空间供新对象生成
1、垃圾判断算法
引用计数算法
- 原理: 对每一个对象都提供一个关联的引用计数,以此来标识该对象是否被使用, 当这个计数为0时, 说明这个对象已经不再被使用了。
- 优点: 算法简单; 并且不用暂停引用, 当计数变为0时, 即可将此的对象的内存空间回收
- 缺点: 无法解决循环引用问题
可达性分析算法
以根集对象为起始点进行搜索,如果有对象不可达的话,即是垃圾对象。这里的根集一般包括java栈中引用的对象、方法区常良池中引用的对象,本地方法中引用的对象等。
2、垃圾回收算法
标记-清除算法(Mark-Swap)
标记-清除算法.png此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。
标记-整理算法(Mark-Compact)
标记整理算法.png标记整理算法类似与标记清除算法,不过它标记完对象后,不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。
复制算法(Copying)
复制算法.png此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。
垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。
此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间
分代算法(Generational)
分代算法.png- 当前商业虚拟的垃圾算法都采用该算法。
- 根据对象存活周期的不同将内存划分为多块(例如:新生代、老年代),根据各个块的特点制定相应的回收策略。
- 新生代中每次收集时都有大部分对象四驱, 只存活少数, 一般采用复制算法
- 老年代存活率高, 一般采用“标记-整理”或“标记-清除”算法
3、HotSpot JVM的分代垃圾清理
上述讲解如何区分垃圾,以及垃圾是如何回收的, 现在我们来看看HotSpot JVM是如何实现垃圾回收的。
HotSpotJVM分代算法.png
- 按照对象存活划分成: 新生代、老年代、持久带
- 新生代分位一个Eden区和两个Survivor区,每次使用一个Eden区和一个Survivor区。默认Eden区与Survivor区的大小比例为8:1
- 回收时将Eden区和Survivor区中还存活的对象拷贝到另一个Survivor区,清理掉Eden区和刚使用过多的Survivor区中的空间。
4、垃圾收集器
如果说垃圾收集算法是方法论, 那么垃圾收集器就是内存回收的具体实现。
常见的垃圾收集器
垃圾收集器 | 适用区 | 类别 | 算法 | 使用场景 |
---|---|---|---|---|
Serial | 新生代 | 串行 | 复制算法 | 单CPU环境下的Client模式 |
ParNew | 新生代 | 并行 | 复制算法 | 多CPU环境时在Server模式下与CMS配合 |
Parallell Scavenge | 新生代 | 并行 | 复制算法 | 在后台运算而不需要太多交互的任务 |
CMS | 老年代 | 并发 | 标记-清除算法 | 集中在互联网站或B/S系统服务端上的Java应用 |
Serial Old | 老年代 | 串行 | 标记-整理算法 | 单CPU环境下的Client模式、CMS的后备预案 |
Parallel Old | 老年代 | 并行 | 标记-整理算法 | 在后台运算而不需要太多交互的任务 |
G1 | 新年代与老年代 | 并行与并发 | 标记-整理算法 | 面向服务端应用,将来替换CMS |
其中:
- 并行(parallel): 指多个收集器的线程同时工作, 但用户线程处于等待状态。
- 并发(concurrent): 指收集器在工作的同时, 可以允许用户线程工作。
- 并行收集器: 吞吐量优化的收集器。
- 并发收集器: 暂停时间优化的收集器。
垃圾收集器的使用
垃圾收集器使用.jpg上图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。
虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器。
Hotspot实现了如此多的收集器,正是因为目前并无完美的收集器出现,只是选择对具体应用最适合的收集器
四、总结
本片文章比较简单介绍了Java虚拟机, 相信对大家对Java虚拟机有了一定的了解。
当然文中很多方面都没进行深入讲解,如果想更深刻的了解原理可以自行购买相关书籍或者网上搜索相关内容进行学习。
推荐学习书籍《深入理解Java虚拟机-JVM高级特性与最佳实践》
参考资料:
- 《深入理解Java虚拟机-JVM高级特性与最佳实践》
- 《Java虚拟机规范(第二版)》
- 《IBM JVM Garbage Collection And Storage Allocation techniques》
喜欢可以关注公众号: 终身幼稚园
终身幼稚园
网友评论