概念
虚拟机:指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统,是物理机的软件实现。JVM分类:VMWare,Visual Box,JVM(其中VMWare和Visual Box都是使用软件模拟物理CPU的指令集 ,而JVM使用软件模拟Java字节码的指令集)
运行机制
图1 jvm运行机制
基本架构
图2 jvm基本架构
Java运行时编译源码(.java)成字节码,然后再由jre(java运行环境)运行。jre是由java虚拟机(jvm)实现。Jvm分析字节码,后解释并执行。JVM由三个主要的子系统构成:
1.类加载器子系统
2.运行时数据区(内存)
3.执行引擎
类加载器子系统
图3 java类生命周期
类装载包括了加载,连接(验证、准备、解析(可选)),初始化。其中类加载工作由ClassLoader及其子类负责。
加载:在硬盘上查找并通过IO读入字节码文件
连接:执行校验、准备、解析(可选)步骤
校验,校验字节码文件的正确性
准备,给类的静态变量分配内存,并赋予默认值
解析,将符号引用转为直接引用
初始化:对类的静态变量初始化为指定的值,执行静态代码块
类加载器体系结构:
图4类加载器体系
1.启动类加载器:负责加载JRE的核心类库,如jre目标下的rt.jar,charsets.jar等.
2.扩展类加载器:负责加载JRE扩展目录ext中JAR类包
3.系统类加载器:负责加载ClassPath路径下的类包
4.用户自定义加载器:负责加载用户自定义路径下的类包
类加载机制:全盘负责委托机制。全盘负责,当一个ClassLoader加载一个类时,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也由这个ClassLoader载入。委托机制:是指先委托父类加载器寻找目标类,只有在找不到的情况下采用自己的路径中查找并载入目标类
运行时数据区
PC寄存器:用来存储待执行指令的地址。分支,循环,跳转,异常处理,线程恢复等功能都需要依赖pc寄存器。若线程执行的时一个java方法,则pc寄存器中保存的是待执行指令的地址。若执行的是一个native方法,则pc寄存器中为空。线程独占。
Java栈(java虚拟机栈):是java方法执行的内存模型,为虚拟机执行java方法,每个方法在执行的同时都会创建一个栈帧(用于存储局部变量表,操作数栈,动态链接,方法出口等信息)。
Jvm对该区域规范了两种异常:1,线程请求的栈深度大于虚拟机栈所允许的深度,将抛出StackOverFlowError异常。2,若虚拟机栈可动态扩展,当无法申请到足够内存空间时将抛出OutOfMemoryError异常。通过jvm参数 –Xss指定栈空间,空间大小决定了函数调用的深度。线程独占。
本地方法栈:为虚拟机执行native方法,其他规范与java栈类似。不同类型的虚拟机对该区域可自由实现。线程独占。
java堆:虚拟机启动时创建,用于存放对象实例。几乎所有的对象在堆上分配内存,当对象无法再该空间申请到内存时将抛出OutOfMemoryError异常。同时也是垃圾收集器管理的主要区域。可通过-Xmx –Xms参数来分别指定最大堆和最小堆。线程共享。
方法区(非堆):存储类信息、常量、静态变量、即时编译器编译后的代码等数据。运行时常量池是其一部分,用于存放编译器生成的各种字面量和符号引用。Jvm规定当方法区无法满足内存分配需求时,将抛出OutOfMemeoryError异常。可通过-XX:PermSize -XX:MaxPermSize参数分别设置永久区的初始空间和最大空间。线程共享。
直接内存:并不是虚拟机运行时数据区的一部分,也不是JVM规范中定义的内存区域。但也在频繁使用,也会发生OutOfMemory异常。
执行引擎
执行引擎读取运行时数据区的字节码并逐个执行
(1)解释器:解释器更快地解释字节码,但执行缓慢,解释一句执行一句。
(2)JIT编译器:JIT编译器消除了解释器的缺点。执行引擎通过解释器转换字节码,当它发现重复的代码时,将使用JIT编译器,它编译整个字节码并将其更改为本地代码。这个本地代码将直接用于重复的方法调用,这提高了系统的性能。
JIT的构成组件为:
中间代码生成器(Intermediate Code Generator):生成中间代码 。
代码优化器(Code Optimizer):负责优化上面生成的中间代码 。
目标代码生成器(Target Code Generator):负责生成机器代码或本地代码 。
分析器(Profiler):一个特殊组件,负责查找热点(被多次调用的方法)
(3)垃圾收集器:收集和删除未引用的对象。可以通过调用“System.gc”触发垃圾收集,但不能保证执行。JVM的垃圾回收对象是已创建的对象。
Java本机接口(JNI):JNI将与本机方法库进行交互,并提供执行引擎所需的本机库。
本地方法库:执行引擎所需的本机库的集合。
垃圾收集
1,如何识别垃圾,判定对象是否可被回收
引用计数:给每个对象添加一个计数器,当有地方引用该对象时计数器加1,当引用失效时计数器减1。用对象计数器是否为0来判断对象是否可被回收。缺点:无法解决循环引用的问题
可达性分析:通过“GC ROOTs”的对象作为搜索起始点,通过引用向下搜索,所走过的路径称为引用链。通过对象是否有到达引用链的路径来判断对象是否可被回收(可作为GC ROOTs的对象:虚拟机栈中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中JNI引用的对象)
2,使用GC算法回收释放垃圾对象所占用的内存空间
区分内存溢出和内存泄露:内存溢出是指程序在申请内存时,没有足够的内存空间供其使用.内存泄露是指在程序在申请内存使用完后,无法释放回收已申请的内存空间
GC算法
按照回收策略划分:标记清除算法,标记整理算法,复制算法
1.标记-清除算法:分为两阶段“标记”和“清除”。首先标记出哪些对象可被回收,在标记完成之后统一回收所有被标记的对象所占用的内存空间。不足之处:1.无法处理循环引用的问题2.效率不高3.产生大量内存碎片(ps:空间碎片太多可能会导致以后在分配大对象的时候而无法申请到足够的连续内存空间,导致提前触发新一轮gc)
图 5标记-清除算法
2.标记-整理算法:分为两阶段“标记”和“整理”。首先标记出哪些对象可被回收,在标记完成后,将对象向一端移动,然后直接清理掉边界以外的内存。
图 6标记-整理算法
3.复制算法:把内存空间划为两个相等的区域,每次只使用其中一个区域。gc时遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。不足之处:1.内存利用率问题2.在对象存活率较高时,其效率会变低。
图 7复制算法
按照分区对待的方式分:增量收集算法,分代收集算法
1.增量收集:实时垃圾回收算法,即:在应用进行的同时进行垃圾回收。
2.分代收集:基于对对象生命周期对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法进行回收。
按系统线程分:串行收集算法,并行收集算法,并发收集算法
1.串行收集:使用单线程处理垃圾回收工作,实现容易,效率较高。不足之处:1.无法发挥多处理器的优势 2.需要暂停用户线程
2.并行收集:使用多线程处理垃圾回收工作,速度快,效率高。理论上CPU数目越多,越能体现出并行收集器的优势。不足之处:需要暂停用户线程
3.并发收集:垃圾线程与用户线程同时工作。系统在垃圾回收时不需要暂停用户线程
GC收集器
垃圾收集算法是内存回收的理论基础,而垃圾收集器就是内存回收的具体实现。
1.Serial/Serial Old收集器是最基本最古老的收集器,它是一个单线程收集器,工作时必须暂停所有用户线程。该收集器采用复制算法主要针对新生代的收集。Serial Old收集器采用标记-整理算法主要针对老年代的收集器。实现简单高效,但会停顿。
2.ParNew收集器是Serial收集器的多线程版本,使用多个线程进行垃圾收集。
3.Parallel Scavenge收集器是一个采用复制算法针对新生代的多线程收集器(并行收集器),不需要暂停其他用户线程。
4.Parallel Old收集器是Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和标记整理算法。
5.CMS(Current MarkSweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它是一种并发收集器,采用的是标记-清除算法。
6.G1收集器是收集器技术发展最前沿的成果,面向服务端应用的收集器,能充分利用多CPU、多核环境。因此它是一款并行与并发收集器,并且它能建立可预测的停顿时间模型。
GC参数
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:SurvivorRatio:设置eden区大小和survivior区大小的比例
-XX:NewRatio:新生代和老年代的比
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩
-XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收
-XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比启动CMS回收
-XX:UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS回收
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发
-XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理
性能分析和监控工具
感兴趣的朋友可自行深入研究下列各工具。
JDK自带命令行工具:
Jps:虚拟机进程状况工具
Jstat:虚拟机统计信息监视工具
Jinfo:虚拟机配置信息工具
Jmap:内存映像工具
Jhat:虚拟机堆转储快照分析工具
Jstack:堆栈跟踪工具
JDK可视化工具:
JConsole:java监视与管理控制台
VisualVM:故障处理工具
想要朝这java程序员发展或者真心有兴趣的。可以加我QQ,找我要一些java的学习视频,这个是免费的,希望同学找我要的时候不要有理所应当的态度,毕竟都是我的心血,希望你是真的有一颗想要学好java的心,我也会尽所能的去帮助你成为一名优秀的程序员。
注:加群要求 学习交流群:642830685
1、想学习JAVA这一门技术, 对JAVA感兴趣零基础,想从事JAVA工作的。
2、工作1-5年,感觉自己技术不行,想提升的
3、如果没有工作经验,但基础非常扎实,想提升自己技术的。
4、还有就是想一起交流学习的。
5.小号加群一律不给过,谢谢。
转发此文章请带上原文链接,否则将追究法律责任
网友评论