JVM原理及回收机制

首先,JVM是什么?

JAVA字节码是在JRE(java runtime environment)中运行,而JRE是由JavaAPI和JVM组成。

JVM (Java Virtual Machine) 是JRE的核心组成,承担了其分析和执行Java字节码的工作,JVM是通过类加载器(Class Loader)加类Java应用,并通过Java API进行执行。

说到JVM,就不得不聊聊它的类加载机制及双亲委托模型:

Java类的生命周期:

加载 --> 链接(验证 --> 准备 --> 解析 )--> 初始化 -->使用 --> 卸载  

双亲委托机制:当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。

如下图:

JVM内存管理及垃圾回收

JVM内存组成结构:堆/栈/本地方法栈/方法区

堆:所有new的对象都在此,堆的大小可以通过一些配置项来控制(-Xmx和-Xms)堆分为新生代,老年代。(具体可参看垃圾回收机制)

栈:每个线程在执行方法时会在栈中申请栈帧,包括局部变量区和操作数栈,用来存放此方法调用过程中的临时变量,参数,结果等。

本地方法栈:支持native方法的执行。

方法区:存放了要加载的类信息,静态变量,final常量,属性,方法信息等。JVM用持久代来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。

垃圾回收机制:

哪些内存需要回收?

未被引用的对象/作用域发生未捕获异常/程序在作用域正常执行完毕/程序执行System.exit()/程序发生意外终止(被杀进程等)

什么时候触发GC?

(1)当应用程序空闲时,即没有应用线程在运行时,GC会被调用。

(2)Java堆内存不足时,GC会被调用。

怎么判断对象是否可被回收?

两种算法:

引用计数

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

优点:简单,高效,现在的objective-c用的就是这种算法。

缺点:很难处理循环引用,相互引用的两个对象则无法释放。

可达性分析(根搜索)

从GC Roots作为起点,向下搜索它们引用的对象,可以生成一棵引用树,树的节点视为可达对象,反之视为不可达。

在Java中,可以作为GC Roots的对象包括下面几种:

虚拟机栈(栈帧中的本地变量表)中的引用对象。

方法区中的类静态属性引用的对象。

方法区中的常量引用的对象。

本地方法栈中JNI(Native方法)的引用对象

回收算法有哪些?

引用计数/标记-清除/复制/标记-整理

JVM在不同的时代用的是不同的回收机制,新时代存活时间端,基于复制算法来进行回收,新生代采用空闲指针的方式来触发GC,当有新的对象需要分配内存时,检查空间是否足够,不够就触发GC。

旧生代存活时间较长,较稳定,采用标记算法来进行回收,标记即找出存活的对象,然后再进行回收未被标记的对象。

方法区的对象也能被回收,只是条件非常苛刻,需要同时满足以下三个条件:

所有实例被回收/加载该类的ClassLoader被回收/Class对象无法通过任何途径访问(包括反射)

JVM内存调优

内存查看工具:JConsole和Java VisualVM

调优目的:减少GC的频率和FULLGC的次数(占有CPU资源,影响吞吐量),尤其避免FULL GC。

出现fullGC的几种情况:

旧生代的空间不足/Pemanet Generation空间不足/System.gc()被显示调用

JVM提供的GC策略设置方式:

吞吐量优先-XX:GCTimeRatio=n/暂停时间优先-XX:MaxGCPauseRatio=n

性能调优的原则:

MinorGC回收原则: 每次minor GC 都要尽可能多的收集垃圾对象。以减少应用程序发生Full GC的频率。

GC内存最大化原则:处理吞吐量和延迟问题时候,垃圾处理器能使用的内存越大,垃圾收集的效果越好,应用程序也会越来越流畅。

GC调优3选2原则: 在性能属性里面,吞吐量、延迟、内存占用,我们只能选择其中两个进行调优,不可三者兼得。

JVM常见配置

堆设置

-Xms:初始堆大小

-Xmx:最大堆大小

-XX:NewSize=n:设置年轻代大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

收集器设置

-XX:+UseSerialGC:设置串行收集器

-XX:+UseParallelGC:设置并行收集器

-XX:+UseParalledlOldGC:设置并行年老代收集器

-XX:+UseConcMarkSweepGC:设置并发收集器

垃圾回收统计信息

-XX:+PrintGC

-XX:+PrintGCDetails

-XX:+PrintGCTimeStamps

-Xloggc:filename

并行收集器设置

-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。

-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间

-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

并发收集器设置

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。

-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

总的来说,JVM的垃圾回收是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象占据内存空间的一种机制。我们通过各种各样的调优方式来实现一个目标:那就是如何使用较小的内存占用来获得较高的吞吐量或者较低的延迟。

你可能感兴趣的:(JVM原理及回收机制)