0. 说明

  转载并修改自JVM


1. JVM

  1.1 什么是JVM

  JVM为Java虚拟机(Java Virtual Machine)

  Runtime data area,运行时数据区。

  包含5个区域,分别为:

  method area         (方法区)

  heap                        (堆)

  java stack           (java栈)

  native method stack     (本地方法栈)

  program counter register。  (程序计数器)

  图示如下:

  1.2 method area(方法区)

  用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码等信息。

  方法区是线程间共享的,当两个线程同时需要加载一个类型时,只有一个类会请求ClassLoader加载,另一个线程会等待。

  1.3 heap(堆)

  虚拟机中用于存放对象与数组实例的地方,垃圾回收的主要区域就是这里(还可能有方法区)。

  如果垃圾收集算法采用按代收集(目前大都是这样),这部分还可以细分为新生代和老年代。新生代又可能分为Eden区,From Survivor区和To Survivor区,主要是为了垃圾回收。所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB)。

  1.4 java stack(java栈)

  虚拟机栈也是线程私有的,每创建一个线程,虚拟机就会为这个线程创建一个虚拟机栈。

  虚拟机栈表示Java方法执行的内存模型,每调用一个方法,就会生成一个栈帧(Stack Frame)用于存储方法的本地变量表、操作栈、方法出口等信息,当这个方法执行完后,就会弹出相应的栈帧。

  栈帧分为三部分:局部变量区(Local Variables)、操作数栈(Operand Stack)和帧数据区(Frame Data)。

  如果请求的栈的深度过大,虚拟机可能会抛出StackOverflowError异常,如果虚拟机的实现中允许虚拟机栈动态扩展,当内存不足以扩展栈的时候,会抛出OutOfMemoryError异常。

1.5 native method stack(本地方法栈)

  与虚拟机栈类似,只是是执行本地方法时使用的。

1.6 program counter register。(程序计数器)

  类似于PC寄存器,是一块较小的内存区域,通过程序计数器中的值寻找要执行的指令的字节码,由于多线程间切换时要恢复每一个线程的当前执行位置,所以每个线程都有自己的程序计算器。这一个区域不会有OutOfMemeryError。当执行Java方法时,这里存储的执行的指令的地址,如果执行的是本地方法,这里的值是Undefined。

1.7 栈 & 堆 溢出

  栈溢出:Stackoverflow

  堆溢出:Out Of Memory


2. JVM从堆角度划分

  2.1 堆 & 非堆 & 离堆堆

   堆用来存放所有的对象和数组,在堆内空间又分为年轻代和年老代。

      • 年轻代

         年轻代分为伊甸区和幸存区。所有对象诞生于伊甸区,然后回收后经过幸存区。

        • 伊甸区

            所有对象诞生于伊甸区。

        • 幸存区

            之所以使用两个幸存区,是为了在每次回收对象后,可以进行内存碎片整理。以利用更有效使用内存。

            一区和二区也称为from区和to区,每次有一个区是空间是空的。但对象回收期间每个幸存区只经过一次。

          • 幸存一区
          • 幸存二区
      • 年老代
  • 非堆

   非堆是JVM内在堆外部分的内存,主要包含代码缓存区、压缩类空间和元数据区。JDK1.8之前称为永久区。

  • 离堆

   离堆是操作系统内JVM之外的内存空间。java可以直接操纵jvm之外的内存空间。

  2.2 参数调整

  jdk1.8之后,没有永久代的概念了,改成了元空间的叫法。而且官方文档上说不会再出现永久区的溢出问题,比如在使用maven进行编译时常常导致的问题。

参数 解释  示例  备注
-Xss 栈大小 -Xss100m  
-Xms 初始堆大小 -Xms100m  
-Xmx 最大堆设置 -Xmx100m  
-Xmn 年轻代设置 -Xmn100m  
-XX:NewSize 年轻代大小 -XX:NewSize=100m  
-XX:MaxNewSize 年轻代最大值 -XX:MaxNewSize=100m  
-XX:NewRatio 年老代是年轻代的倍数 -XX:NewRatio=3,默认2  
-XX:SurvivorRatio 伊甸区是单个幸存区的倍数 -XX:SurvivorRatio=1,默认6  
-XX:MetaspaceSize 元空间大小 -XX:MetaspaceSize=1g not work
-XX:MaxMetaspaceSize 最大元空间  -XX:MaxMetaspaceSize=2g not work
-XX:CompressedClassSpaceSize 压缩类空间 -XX:CompressedClassSpaceSize=2g not work
-Xverbosegclog 记录gc详细日志到文件 -Xverbosegclog:/home/1.log WAS(Websphere application server)中使用
-Xloggc 记录gc日志 -Xloggc:/home/1.log JDK非标选项

3. JVM相关工具

  3.1 jvisualvm

  打开:Windows+R   -->    jvisualvm

  打开IDEA中运行程序,就能看到 jvisualvm 界面中的情况

  将所有区设为100M:

  -Xms400m -Xmx400m -Xmn300m -XX:SurvivorRatio=1

  3.2 jconsole

  打开IDEA中运行程序 

  打开:Windows+R   -->   jconsole

  3.3 jmap

  3.4 jstat

  • jstat查看帮助

  • 查看jstat选项

  • 查看jstat的gc情况

1秒钟1采样,采样100个样本,数字是进程id

  • 各字段含义
列名 说明
S0C 幸存一区容量(Survivor,Capacity,KB)
S1C 幸存二区容量
S0U 幸存一区使用的大小(Utility,KB)
S1U 幸存二区使用的量
EC 伊甸区容量
EU 伊甸区使用量
OC 年老代容量
OU 年老代使用量
MC 方法区容量
MU 方法区使用量
CCSC 压缩类空间容量
CCSU 压缩类空间使用量
YGC 年轻代gc次数
YGCT 年轻代gc时间
FGC Full GC次数
FGCT Full GC时间
GCT GC总时间,FCCT + YGCT

4. GC

  4.1 什么是GC

  GC 垃圾回收(garbage collection)

  主要作用是回收程序中不再使用的内存

  为了减轻开发人员的工作,同时增加系统的安全性和稳定性,java语言提供了垃圾回收器来自动检测对象的作用域,可自动地把不再被使用的存储空间释放掉。主要的任务是:分配内存,回收不再被引用的对象的内存空间。

  对象回收的前提是没有任何引用能够直接或间接到达他。

  Java程序中显式将对象置为null是个不错的操作,起码保证了对象被回收的前提条件,但是显式调用System.gc()会显著降低系统性能。

  年轻代上发生的gc称为minor gc。java程序中,大部分的对象是“夭折”的,意思就是对象在minor gc的时候就被回收掉了,没有多少对象会进入到年老代。

  年老代上发生gc称为full gc或major gc,minor gc没有回收掉的对象会拷贝到年老代中。

  元空间(jdk1.8之前称为永久代),也就是方法区存放的是类常量以及字符串常量。该区域也会发生gc,并且这部分的gc也算作major gc。

  4.2 相关概念

  并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。

  并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行。而垃圾收集程序运行在另一个CPU上。

  4.3 GC类型

  • 1. Serial GC

  串行gc,配置参数为:   -XX:+UseSerialGC 。

  采用“mark-sweep-compact”算法,mark是标记依然存活的对象,sweep清理掉回收的对象,compact是压紧内存空间,可以理解为内存碎片整理。

  使用一个线程执行gc,串行gc很少使用。

  • 2. Parallel GC

  并行gc,配置参数为:  -XX:+UseParallelGC。

  串行gc使用一个线程执行gc,并行gc使用多个线程执行gc,因此在多核或是内存充足的情况下可以使用。串行gc很少使用。

  • 3. Parallel Old GC

  在JDK5之后才出现的算法,与并行gc算法的不是是针对年老代gc的算法采用的是“mark-summary-compact”。summary和sweep的不同是将gc之后幸存的对象放置到gc余弦处理好的不同区域,算法相对sweep来讲稍微复杂些。

  配置参数为:  -XX:+UseParallelOldGC

  • 4. CMS GC

  并行gc,该算法相较于之前的gc算法复杂得多。过程是“mark-sweep”阶段,没有了compact阶段。而且mark阶段又分成了initial mark和mark,其中initial mark需要stop-the-world,但是时间非常短,这一步主要是查找那些距离类加载器非常近的对象。之后的mark阶段是可以并行,即不需要stop-the-world,该步骤中,所有被幸存对象引用的对象会被确认是否已经被追踪和校验。remark阶段正如其名称一样,再一次检查那些在并行标记中增加或删除的对象,相当于验证过程。最后的并行sweep阶段开始执行gc过程,一旦采用该中gc,由gc导致的暂停时间非常短暂。因此CMS GC也叫低延迟gc,常用对响应时间非常苛刻的场景下。但CMS GC也有缺点:

    占用更多的内存和cpu

    默认不支持compact操作

  如果因为碎片过多,导致不得不执行compact操作时,stop-the-world时间要比其他任何gc都要长,需要考虑compact任务的发生频率和执行时间。

  配置参数为:  -XX:+UseConcMarkSweepGC

  • 5. G1 GC

  G1类型是垃圾回收优先类型,在jdk1.7才正式发布的一个算法。G1的结构如图:

  

  在该类型下,不再有年轻代和年老代的概念。如图所示,每个对象被分配到不同的格子,随后执行gc。一个区域装满后,对象被分配到另一个区域,并执行gc。中间不再有从年轻代到年老代转义的三个步骤了。该类型为替代CMS类型而创建,因为CMS在长时间持续运行时导致很多问题。

  配置参数为:  -XX:+UseG1C

G1的最大好处是性能,他比任何一种GC都快,但是一定要在成熟的jdk版本上使用它。

总结

收集器 串行、并行or并发 新生代/老年代 算法 目标 适用场景
Serial 串行 新生代 复制算法 响应速度优先 单CPU环境下的Client模式
Parallel 并行 新生代 复制算法 吞吐量优先 在后台运算而不需要太多交互的任务
Parallel Old 并行 老年代 标记-整理 吞吐量优先 在后台运算而不需要太多交互的任务
CMS 并发 老年代 标记-清除 响应速度优先 集中在互联网站或B/S系统服务端上的Java应用
G1 并发 both 标记-整理+复制算法 响应速度优先 面向服务端应用,将来替换CMS

  4.4 Demo

  Hello类

 class Hello
{
public static void main(String[] args) throws Exception
{
//指定循环次数
int count = Integer.parseInt(args[0]) ;
//指定byte数组大小
int size = Integer.parseInt(args[1]) ;
for (int i = 0 ; i<= count ; i++) {
byte[] bytes = new byte[size] ;
}
}
}

测试类中的 testProcess() 方法,测试5种垃圾回收类型所需要的时间

 @Test
public void testProcess() throws Exception {
//5中gc算法
String[] gcs = {
"UseSerialGC" ,
"UseParallelGC" ,
"UseParallelOldGC" ,
"UseConcMarkSweepGC" ,
"UseG1C"
} ; Runtime r = Runtime.getRuntime(); for(String gc :gcs){
System.out.print(gc + "\t: ");
for(int i = 0 ; i < 3 ; i ++){
String javapc = String.format("java -Xms500m -Xmx500m -XX:NewSize=7m -XX:MaxNewSize=7m -XX:SurvivorRatio=5 -XX:+%s -cp d:/java Hello 10000 6000000" , gc) ;
long start = System.nanoTime() ;
Process p = r.exec(javapc);
p.waitFor();
System.out.print((System.nanoTime() - start) + "\t");
}
System.out.println();
}

  4.5 GC过程

  GC 的回收过程是伊甸区已满,向幸存区的to区回收,同时幸存区的from区也会向to进行回收,注意幸存区有两个,同一时刻只有一个幸存区是空的,from区和to区会交替进行角色交换,但是对象在回收过程中只经过一次从from到to的过程,如果对象仍没有回收掉,就会进入到年老代。

  

  4.6 GC优化

  GC时,除了 GC 所需要的线程外,app的所有线程都会暂停,直到 GC 过程结束。因此有stop-the-world一次的说法。

  对 GC 的优化,很多时候也是指要减少stop-the-world的时间。


JVM & GC 笔记的更多相关文章

  1. JVM GC笔记

    堆分区:所有new的对象都会存放在堆中      > 新生代(Young Generation):存放生命周期短的对象,具体还分为Eden和Survivor两个区,其中Survivor分为Fro ...

  2. 【Java虚拟机】JVM学习笔记之GC

    JVM学习笔记二之GC GC即垃圾回收,在C++中垃圾回收由程序员自己来做,例如可以用free和delete来回收对象.而在Java中,JVM替程序员来执行垃圾回收的工作,下面看看GC的详细原理和执行 ...

  3. JVM学习笔记(四)------内存调优【转】

    转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内 ...

  4. JVM学习笔记(四)------内存调优

    首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提 ...

  5. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...

  6. jvm内存JVM学习笔记-引用(Reference)机制

    在写这篇文章之前,xxx已经写过了几篇关于改jvm内存主题的文章,想要了解的朋友可以去翻一下之前的文章 如果你还不了解JVM的基本概念和内存划分,请阅读JVM学习笔记-基础知识和JVM学习笔记-内存处 ...

  7. JVM学习笔记-JVM模型

    JVM学习笔记 == 标签(空格分隔): jvm 学习笔记全部来自于<深入理解java虚拟机>总结 jvm内存示意图 虚拟机栈(Java Virtual Machine Stacks): ...

  8. JVM 学习笔记记录

    JVM 学习笔记记录 Sun JDK 监控和故障处理工具 名称 主要作用 jps JVM Process Status Tool, 显示指定系统内所有的HotSpot虚拟机进程 jstat JVM S ...

  9. JVM学习笔记-第三章-垃圾收集器与内存分配策略

    JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...

随机推荐

  1. setup&hold

    setup time:建立时间,也就是在时钟上升沿到来前,数据需要稳定的时间.hold time:保持时间,指的是在时钟上升沿到来后,数据还需要保持的时间.实际上设置setup time和hold t ...

  2. php功底你修炼到哪一级

    第一阶段:基础阶段(基础PHP程序员) 重点:把LNMP搞熟练(核心是安装配置基本操作) 目标:能够完成基本的LNMP系统安装,简单配置维护:能够做基本的简单系统的PHP开发:能够在PHP中型系统中支 ...

  3. Spark2.1.0模型设计与基本架构(下)

    阅读提示:读者如果对Spark的背景知识不是很了解的话,建议首先阅读<SPARK2.1.0模型设计与基本架构(上)>一文. Spark模型设计 1. Spark编程模型 正如Hadoop在 ...

  4. SQLServer之视图篇

    1 视图介绍          视图是从一个或者几个基本表(或视图)导出的表.它与基本表不同,是一个虚表.数据库中只存放视图的定义,而不存在视图对应的数据,这些数据仍然存放在原来的基本表中.所以一旦基 ...

  5. [日常] Go语言圣经-Deferred函数

    1.只需要在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法.当defer语句被执行时,跟在defer后面的函数会被延迟执行.直到包含该defer语句的函数执行完毕时,defe ...

  6. Java基础——详尽说明try-catch-finally的用法

    问:Java异常处理机制,理解了吗?Java异常处理,真的掌握了吗?什么是自定义异常?catch体里遇到return 是怎么处理?finally 体里有return怎么处理?catch 和 final ...

  7. 逆向工程生成的mybatis中mapper文件。mapper接口,实例化成对象

    逆向工程生成的mybatis中mapper文件中,*mapper文件只是接口,而不是类文件.但是却可以通过spring的容器获得实例. 例如: //1.获得mapper代理对象,从spring容器获得 ...

  8. 方程整数解-2015省赛C语言A组第一题

    方程整数解 方程: a^2 + b^2 + c^2 = 1000(或参见[图1.jpg])这个方程有整数解吗?有:a,b,c=6,8,30 就是一组解.你能算出另一组合适的解吗? 请填写该解中最小的数 ...

  9. Charlie's Change(完全背包+路径记忆)

    Charlie's Change Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3176   Accepted: 913 D ...

  10. C#里面的事物回滚,解决同步数据插入时出现重复数据

    什么是事物回滚: 举个栗子,你在你家的银行分行取钱,取完钱数据要同步,而且可能每个分行都有一个存储这些数据的数据库,分行的这些 存取的记录都需要实时同步,如果你取完500刚好断电了,好嘛,分行可能刚记 ...