JVM的小总结(转)
ref:http://www.cnblogs.com/ityouknow/p/6482464.html
注1:看了大神:纯洁的微笑的JVM系列篇,发现好多地方还是似懂非懂,理解的并不透彻,jvm的调优部分更是稀里糊涂;
本片主要整理下jvm部分的知识点,方便以后的面试使用,(权且死记硬背了 !>_<!)
注2:由于不同的JVM厂商不同,关于JVM的分区,存在几个不确定的地方,以下简述对这些不甚明了的地方的个人理解,难免有误:
1、关于JVM的内存划分,“方法区”的叫法是JVM的规范中的术语,而Oracle公司的HotSpot虚拟机对方法区的实现是永久代(PerGen space),所以只有HotSpot才有永久带,也就有了对永久带的配置参数-XX:PermSize,网上的JVM的分析大多对于HotSpot的,但要明白“方法区”与“PerGen space”两者不是等价的。
2、JDK8中废弃了永久带(PermGen),启用了元空间(Metaspace)
ref:https://www.cnblogs.com/yulei126/p/6777323.html
ref:http://www.cnblogs.com/paddix/p/5309550.html
废弃原因:
- PermGen现实中经常爆OutOfMemoryError异常,hotspot中有参数实现PerGen空间的配置
- oracle公司融合自身HotSpot JVM与 JRockit VM两种虚拟机,后者没有永久带,不需要配置;
- (永久代会为 GC 带来不必要的复杂度,并且回收效率偏低)
元空间Metaspace也是对方法区的实现,作用同以前的PermGen,其最大不同在于:Metaspace不在JVM中,而是使用本地内存(即JVM以外的本机内存)存放。因此,默认情况下Metaspace只收到本机内存的限制,同样也可以通过参数指定如:-XX:MetaspaceSize等。
JDK1.7中,就已经将PermGen中的部分数据转移到其他地方存储:如类的静态变量转移到Heap区,字符串也在Heap区???
<---------------------------------------------------------------------正片开始----------------------------------------------->
jvm的体系梳理
- 类的加载机制
- JVM的内存结构
- GC算法 垃圾回收
- GC分析 命令调优
注:底部给出思维导图参考
1、类的加载机制
1.1:什么是类的加载:
(1)将类的.class文件以二进制读入到内存,放入运行时数据区的方法区,然后在堆区创建一个java.lang.Class对象,以封装类在方法区的数据结构。
(2)类加载的最终产品是位于堆区的Class对象,该Class对象封装类在方法区的数据结构,并向JAVA程序员提供了访问方法区内数据解耦的接口。
1.2:类的生命周期:

####: 类的生命周期:
#---- 类的加载
|---- 装载(Loading)(为了区分加载,这里称其为装载):查找并导入类的Class文件,在堆区创建java.lang.Class的对象。
|---- 连接过程分为三块:
|---- 验证:文件的格式、元数据、字节码、符号引用验证,确保被装载的类的正确性,该阶段虽然重要但不是必须的;
|---- 准备:为类的静态变量(static)分配内存,并将其初始化为默认值;如 public static int value=3 ,此时value的值是0而不是3;而对于: public static final int value=3 ,该阶段value的值是3,而不是0,可以认为final static 常量在javac的编译期间,为value生成了ConstantValue属性,准备阶段jvm根据ConstantValue的值为value指定值。
|---- 解析:将符号引用转换为直接引用;
|---- 初始化:为类的静态变量,静态代码块等赋予正确的初始值。
#---- 类的使用:new出对象供程序使用。
#---- 类的卸载:执行垃圾回收。
补充问题:
1.2.1:JVM的初始化步骤(初始化过程):
- 假如这个类还没有被加载和连接,则程序先加载并连接该类;
- 假如这个类的父类还没有被初始化,则先初始化其直接父类;
- 假如类中有初始化语句,则系统依次执行这些初始化语句。
1.2.2:类的初始化时机:
- new创建类的实例时;
- 访问某个类或接口的静态变量,或者对该静态变量赋值;
- 调用类的静态方法;
- 反射(Class.forName("com.wht.Test"));
- 初始化某个类的子类时,父类也会进行初始化;
- JVM启动时被标明为启动类的类
1.2.3:哪几种情况下,JVM会结束生命周期:
1、执行了system.exit();
2、程序正常结束;
3、执行过程中发生异常或错误而终止;
4、操作系统的错误导致JVM的进程终止;
1.3:类加载器

- 启动类加载器:Bootstrap ClassLoader,负责加载JDK\jre\lib目录下或被-Xbootclasspath指定位置处,可悲jvm识别的类库;
- 扩展类加载器:Extension ClassLoader,负责加载JDK\jre\lib\ext目录下或由java.ext.dirs系统变量所指定路径中的所有类库;开发者可以直接使用该加载器;
- 应用程序加载器:ApplicationClassLoader,负责加载用户类路径(Classpath)所指定的类,开发者可以直接使用该类加载器;
类的加载机制:
- 全盘负责:某个类加载器负责加载某个Class,对该Class所依赖和引用的其他Class都由该加载器负责加载,除非显示指定。
- 父类委托(双亲委托机制):某个类加载器收到Class加载请求时,现将该请求转至父类加载器,对Class进行加载,父类找不到该类无法完成加载,才尝试自己加载。
- 缓存机制:所有加载过的Class都会被缓存,当程序中需要使用某个类时,类加载器先从缓存区寻找该Class,不存在,才会读取Class的二进制,生成Class对象存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。
2、JVM内存结构

| 方法区和堆是所有线程共享的内存区域;而java栈、本地方法栈和程序计数器是运行是线程私有的内存区域。 |
- 堆Heap:存放实例对象,是JVM内存中最大的一块,也是GC的主要区域。
- 年轻代(8:1:1)
- Eden空间
- From Survivor空间
- To Survivor空间
- 老年代
- 年轻代(8:1:1)
- 方法区Method Area:存放被jvm加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 程序计数器(Program Counter Register):是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
- 栈:
- JVM栈:描述方法执行的内存模型,每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
- 本地方法栈(Native Method Stacks):同JVM栈,只不过它是为JVM的Native方法服务;
对象分配规则:
注:相关Minor GC、Major GC&Full GC参见:
ref1:http://www.importnew.com/15820.html :这是翻译的外国人的总结,感觉有些生硬;
ref2 : http://www.cnblogs.com/hnrainll/p/3410042.html :来自博客园,解释的很好,简单明了;
说明:
- 对象优先分配在Eden区,Eden区是连续的内存空间,如果Eden去没有足够的空间,JVM进行一次minor GC或Young GC(即从年轻代回收内存),将剩余的对象复制到一个Survivor区;
- 大对象直接进入老年代(需要大量连续内存空间的对象),以避免在Eden和两个survivor区间的大量内存拷贝。(新生代采用复制算法收集内存)
- 长期存活的对象进入老年代。JVM为每一个对象定义了一个年龄计数器,如果经过1次minor GC后,则进入survivor区,之后每一次Minor GC,该对象的年龄加1,直到达到阈值进老年区。
- 动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,那年龄大于或等于该年龄的对象进入老年区。
- 空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区剩余值的大小,则进行一次Full GC;如果小于检查HandlePromotionFailure设置,如果出现true则只进行Monitor GC,如果false,则进行Full GC。
注:另外网上还有另一种回答:
- Survivor切换:每次的Minor GC都会将剩余对象添加到该Survivor区,当该Survivor满了以后,将其中活着的复制进另一个Survivor区,以后的Minor GC将或者的对象添加到切换后的Survivor区,两个Survivor总有一个是空的。
- 进入老年代:当在两个Survivor间切换了几次(HotSpot默认15次),将其中仍然存活的对象,复制到老年代。
- Full GC:老年代空间一般较大,当老年代内存不足时,出发Major GC.(Full GC与Major GC的区别网上不清楚,参照ref1)
各个内存区域的控制参数大小:
- -Xms 设置堆的最小空间;
- -Xmx设置堆的最大空间大小;
- -XX:NewSize设置新生代最小空间大小。
- -XX:MaxNewSize设置新生代最大空间大小。
- -XX:PermSize设置永久代(方法区)最小空间大小。(JDK1.8废弃PermGen)
- -XX:MaxPermSize设置永久代(方法区)最大空间大小
- -Xss设置每个线程的堆栈大小。
- 老年代的空间设置:Xms(Xmx)-XX:NewSize(MaxNewSize)进行设置;
3、GC算法 垃圾回收:
3.1、对象存活条件判断:
引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,释放时减1,为0时回收。但无法解决对象相互循环引用的问题;
可达性分析:从GC roots开始向下搜索,搜索走过的路径称为引用链。当一个对象到GC roots没有任何引用链相连时,证明此对象是不可用的,不可达对象。
3.2、GC 算法:
- 标记-清除算法(Mark-Sweep) :第一阶段标记处所有需要回收的对象,第二阶段统一回收所有被标记的对象。
- 复制算法(Copying) :将可用内存按容量大小划分为相等的两块,每次只使用一块。当前块用完了,则将还活着的对象复制到另外一块上,并把当前块内存清空。
- 标记-压缩算法 :标记过程同Mark-Sweep算法,标记完成后,让所有存活的对象向一端移动,清理掉端边界以外的内存。
- 分代收集(Generational Collection):将JAVA堆分为年轻代和老年代,分别采用不同的收集算法(年轻代:复制;老年代标记整理)。
3.3、GC回收器
垃圾回收器是对GC算法的实现:
- Serial收集器:是最古老、最稳定、效率高的收集器。参数控制:-XX:+UseSerialGC
- 单个线程串行GC;
- 新生代复制算法、老年代标记压缩;
- GC过程中会Stop-the-world。
- ParNew收集器:是Serial收集器的多线程版本;参数控制:-XX:+UseParNewGC ParNew收集器 -XX:ParallelGCThreads 限制线程数量。
- 新生代并行GC,老年代串行GC;
- 新生代复制算法、老年代标记压缩;
- GC过程会Stop-the-world。
- Parallel收集器:类似于ParNew,更关注系统的吞吐量(用户代码运行时间/总运行时间)
- 新生代复制算法、老年代标记压缩;
- 老年代串行;
- Parallel Old收集器:参数控制: -XX:+UseParallelOldGC 使用Parallel收集器+ 老年代并行
- 多线程+标记-整理算法
- 多线程+标记-整理算法
- CMS收集器:以获取最短的回收停顿时间为目标。
- 优点:并发收集、低停顿。
- 缺点:大量空间碎片,并发降低吞吐量。
- 步骤:
- 初始标记:仅标记GC roots直接关联到的对象,stop-the-world;
- 并发标记:可达性分析的过程,时间较长。
- 重新标记:修正阶段2因程序继续运行造成的不分对象的标记变动。stop-the-world;
- 并发清除:并发,时间较长。
4、GC分析 命令调优
JVM调优就是根据GC的日志分析JVM的内存分配、回收的情况来调整各区域的内存比例或GC回收的策略。???
4.1、GC日志分析
young gc日志格式:

full gc日志格式:
4.2、JVM调优命令
运用jvm自带的命令,可以方便的在生产监控和打印堆栈日志信息中帮助开发者定位问题。
Sun的JDK监控和故障处理命令主要有以下:
- jps:JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
- jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
- jmap,JVM Memory Map命令用于生成heap dump文件
- jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
- jstack,用于生成java虚拟机当前时刻的线程快照。
- jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。
4.1.1:jps(JVM process status tool)显示指定系统内所有HotSpot的进程。格式:
jps [options] [hostid]
- l :输出主类全名或jar路径;
-q :只输出LVMID;
-m:输出jvm启动时传递给main()的参数;
- v:输出jvm启动时显示指定的jvm启动参数;
4.1.2:jstat(JVM statistics Monitoring)用于监视虚拟机运行时状态信息的命令,可以显示虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据;
jstat [option] LVMID [interval] [count] : 操作参数 本地虚拟机进程ID 连续输出时间间隔 连续输出的次数
jstat -gc 1262 2000 20 /*每隔2000ms输出1262的gc情况,输出20次
-class : 显示ClassLoader的行为统计;
-compiler:输出JIT编译过的方法数量耗时;
-gc :垃圾回收堆的行为统计;
-gccapacity:输出堆的各区域的最大最小空间;
-gcutil :输出堆的各区域已用空间占总空间的百分比;
-gccause :垃圾收集统计概述;
-gcnew :统计新生代行为;
-gcnewcapacity:统计新生代的内存空间;
-gcold :统计旧生代行为;
-gcoldcapacity :统计旧生代的大小和空间;
-gcpermcapacity:永生代的行为统计;
printcompilation :hotspot编译方法统计;
4.1.3:jmap(jvm memory map)用于生成heap dump文件(进程所使用内存情况的一次快照)。
jmap [option] LVMID
4.1.4:jhat(JVM heap analysis tool)与jmap搭配,分析jmap生成的dump;
4.1.5:jstack :jstack用于生成java虚拟机当前时刻的线程快照;
4.1.6:jinfo:实时查看和调整虚拟机的运行参数。
4.3、调优工具:
常用调优工具分为两类,
jdk自带监控工具:jconsole和jvisualvm(jdk/bin目录下)
第三方有:MAT(Memory Analyzer Tool)、GChisto。
- jconsole:Java Monitoring and Management Console是从java5开始,在JDK中自带的java监控和管理控制台,用于对JVM中内存,线程和类等的监控
- jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等
- MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗
- GChisto,一款专业分析gc日志的工具
<---------------------------------------------------------------------------------------------------------->

JVM的小总结(转)的更多相关文章
- JVM(七),JVM面试小知识
七.JVM面试小知识 1.JVM三大性能调优参数 -Xms -Xmx -Xss 的含义 2.java内存模型中堆和栈的区别 3.不同JDK版本中的intern()方法的区别
- 启动 jvm 参数小总结
1.启动某项目 nohup java -jar -Xms256m -Xmx512m -Dspring.config.location=/config/application.yml -Dfile.en ...
- JVM的小理解
1.开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件),再然后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器 ...
- jvm的小练习
代码如下: public static void main(String[] args) { byte[] array= new byte[1024*1024]; array=new byte[102 ...
- Java 知识笔记 - 类、集合、多线程、IO、JVM(最后一次更新,2019年02月17日)
目录 Class 内部类.静态内部类.匿名内部类.局部内部类 Collection Java Collection Set Queue Map Collections Arrays System Co ...
- 「每日五分钟,玩转JVM」:对象从哪来
面向对象 众所周知,Java是一门面向对象的高级编程语言,那么现在问题来了,对象从哪来呢?有些人会说通过new关键字来创建一个对象,说的很好,本篇我们就来解密在new一个对象的过程中,JVM都给我们做 ...
- RocketMQ_问题_启动报错,修改堆内存大小
1.启动broker报错 虚拟机内存小,导致虚拟机中的JVM内存小,进而在启动broker时分配JVM内存遇到问题 查询网上得知,查看/usr/local/rocketmq-all-4.3.0/dis ...
- LVS+keeplived+nginx+tomcat高可用、高性能jsp集群
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://kerry.blog.51cto.com/172631/557749 #!/bin ...
- 干货 Elasticsearch 知识点整理二
目录 root object mate-field 元数据字段 mapping-parameters 动态mapping(dynamic mapping) 核心的数据类型 精确匹配与全文检索 精确匹配 ...
随机推荐
- Abp 异常处理
Abp 异常处理 最近一直在读代码整洁之道,我在读到第三章函数的3.9 使用异常替代返回错误码,其实在我的开发经历中都是使用返回错误码给到前端,之前在阅读ABP官网文档中就有看到过使用异常替代异常的做 ...
- 在 WPF 客户端实现 AOP 和接口缓存
随着业务越来越复杂,最近决定把一些频繁查询但是数据不会怎么变更的接口做一下缓存,这种功能一般用 AOP 就能实现了,找了一下客户端又没现成的直接可以用,嗐,就只能自己开发了. 代理模式和AOP 理解代 ...
- Win10 装好 Hyper-V 又要将其卸载方法记录
现需要在 windows 上安装虚拟机使用 linux 系统,遂想起来 win10 本身就有 Hyper-V 虚拟工具,但是 win10 家庭版并没有这个服务,百度之,找到了方法(Win10家庭版怎么 ...
- 大家好 这里是yi术家
好久没有来打卡了的说,可能你以为我忽然一时的热度刷题,但是事情并不是这样. 我在之前的章节里写到,我觉得每天的打卡有点浪费资源和时间,所以决定一周打一次卡. 可是上周好像也忘了打卡的样子. 这样任性的 ...
- Hook(钩子技术)基本知识讲解,原理
一.什么是HOOK(钩子) API Windows消息传递机制,当在应用程序进行相关操作,例如点击鼠标.按下键盘,操作窗口等,操作系统能够感知这一事件,接着把此消息放到系统消息队列,然后到应用程序的 ...
- Ng ML笔记
目录 一.线性回归 1,假设函数.代价函数,梯度下降 2,特征处理 3,代价函数和学习速率 4,特征和多项式回归 5,正规方程 二.逻辑回归(Logistic Regression,LR) 1,假设函 ...
- rlwrap的使用
转至:http://blog.itpub.net/429786/viewspace-776177/ 在LINUX下使用ORACLE一些命令时(如sqlplus,rman等),经常需要调用上次或之前运行 ...
- AndroidMainifest.xml文件属性
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package=" ...
- 列表生成式 生成器 迭代器 yield
列表生成式 格式:通过一个或者若干个在List里边的for构建List而非List外部的for循环 举个例子:计算从1到10整数的平方构成一个List L=[ x*x for x in range(1 ...
- petite-vue-源码剖析-v-for重新渲染工作原理
在<petite-vue源码剖析-v-if和v-for的工作原理>我们了解到v-for在静态视图中的工作原理,而这里我们将深入了解在更新渲染时v-for是如何运作的. 逐行解析 // 文件 ...