jvm 虚拟机 探秘 结构 内容 gc 算法 gc 选择 和不同场景配置 示例

265 阅读10分钟

目录

1.介绍

2.虚拟机组成

2.1.数据隔离区域

2.1.1.程序计数器

2.1.2.jvm虚拟机栈

2.1.3.本地方法栈

2.2.数据共享区域

2.2.1方法区

2.2.2java堆

3.垃圾回收器,及算法思路

3.1 标记 —— 清除算法

3.2复制算法

3.3标记-整理算法

3.4 分代回收

4.使用思路

4.1新生代

4.2老年代

5.java gc 收集器 及配置

并发并行简介

吞吐量优先的垃圾收集器

响应时间优先并发收集器

配置汇总一下



1.介绍

介绍下jvm组成部分和运转方式,以及gc 实现方法简单介绍

  • jvm包括,程序计数器、虚拟机栈、本地方法栈、方法区、java堆

  • 程序计数器、虚拟机栈、本地方法栈是线程数据隔离区域

  • 方法区和java堆数据共享

  • 线程运行使用的就是隔离区域的服务,来做支持,线程共享区域的方法区和堆做具体线程

  • 程序gc 算法和思路

  • 1.标记清除法,就是加标记然后查看标记清除

  • 2复制算法,对一个伊甸园一个幸存者,进行向后复制,到第二个辛存者区域,在往后复制到老年代

    • 所以 年轻代 占用 3/1 小点,因为用的快,老年代 占用3/2   

      • 年轻代 伊甸园 占用 10/8  俩个幸存者 各站 10/1  这样用赋值算法的时候,就只有最右一个幸存者使用的不频繁,也就是常说的10%年轻代留下10%不常用的,剩下的90%利用起来,如此,复制的时候  一个伊甸园和一个幸存者发现对象还有引用或标记,就往后复制,幸存者复制地方不够,就直接复制到带
  • 3.标记整理算法,主要针对老年代用,标记起来把长期存活的放到一端

  • 4.分代回收,划分年轻代和老年代,不同代使用不同算法

 

 

2.虚拟机组成

2.1.数据隔离区域

2.1.1.程序计数器

  • 内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成

2.1.2.jvm虚拟机栈

  • 线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表操作数栈动态链接方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。
  • 局部变量表:存放了编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址)
  • StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。
  • OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。 

2.1.3.本地方法栈

  • 区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。也会有 StackOverflowError 和 OutOfMemoryError 异常。

 

2.2.数据共享区域

2.2.1方法区

  • 对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。

2.2.2java堆

  • 属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

 

3.垃圾回收器,及算法思路

3.1 标记 —— 清除算法

  • 直接标记清除就可。

 

3.2复制算法

  • 把空间分成两块,每次只对其中一块进行 GC。当这块内存使用完时,就将还存活的对象复制到另一块上面。
  • 解决前一种方法的不足,但是会造成空间利用率低下。因为大多数新生代对象都不会熬过第一次 GC。所以没必要 1 : 1 划分空间。可以分一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 空间和其中一块 Survivor。当回收时,将 Eden 和 Survivor 中还存活的对象一次性复制到另一块 Survivor 上,最后清理 Eden 和 Survivor 空间。大小比例一般是 8 : 1 : 1,每次浪费 10% 的 Survivor 空间。但是这里有一个问题就是如果存活的大于 10% 怎么办?这里采用一种分配担保策略:多出来的对象直接进入老年代。 

 

3.3标记-整理算法

  • 不同于针对新生代的复制算法,针对老年代的特点,创建该算法。主要是把存活对象移到内存的一端。

 

3.4 分代回收

  • 根据存活对象划分几块内存区,一般是分为新生代和老年代。然后根据各个年代的特点制定相应的回收算法。

 

4.使用思路

4.1新生代

每次垃圾回收都有大量对象死去,只有少量存活,选用复制算法比较合理。

 

4.2老年代

老年代中对象存活率较高、没有额外的空间分配对它进行担保。所以必须使用 标记 —— 清除 或者 标记 —— 整理 算法回收。

 

 

5.java gc 收集器 及配置

jvm gc 更具业务需要主要分三类: 串行收集器、并发收集器、并行手机器

并发并行可以看我的文章:java 多线程  yushen.blog.csdn.net/article/det…

串行收集器只适合小型数据,我们这里主要介绍介绍  并发和并行收集器 jkd1.5之前都是 使用串行收集器,如果使用其他收集器需要启动的时候配置加入响应的参数,jdk1.5之后系统会进行自动判断

并发并行简介

并行:是多条垃圾收集器 并行执行,但用户线程任然是等待状态

并发:指用户线程和垃圾收集器同是执行,不一定是并行大概率是交叉运行

 

吞吐量优先的垃圾收集器

并行收集器主要以达到一定吞吐量位目的,适用于人工智能,后台处理、这类的高速运行类,使用俩种收集器:

1.并行收集器(-XX:UseParallelGC):次要回收使用多线程执行,主要回收用单线程执行

2.并行旧生代收集器(-XX:UseParallelOldGC)次要回收和主要回收都用单线程,当老年区填满后触发主要回收

常用配置:

java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:UseParallelGC -XX:ParallelGCThreans=20

  • -Xmx 最大堆大小
  • -Xms 初始化堆大小 这个可以和-Xmx 设置一相同,以避免每次垃圾收器收集完毕后JVM重新分配内存。
  • -Xmn 年轻代 设置了2g 这玩意一般是 全堆的 3/1  sum 官方推荐 8/3 (内存大小是 年轻+老年代+持久代(持久代一般固定大小64m))
  • -Xss 设置每个线程的堆大小 jdk1.5之后每个堆大小是1m,以前每个线程堆大小256k,更具线程需要进行对应大小调整,减少这个值能出现更多线程,但是一般系统会对进程设置上限线程数,不能无限生成,经验3千到5千个左右。
  • -XX:UseParallelGC  并行收集器,此配置只对年轻代有效,年轻代用并行,老年代还是用串行收集。
  • -XX:ParallelGCThreaes=20 并行收集器的线程数量,这配置最好和处理器数目一致最好。

java -Xmx3500m -Xms3500m -Xmn2g -Xss128k -XX:UseParallelGC -XX:UseParallelGCThreaes=20 -XX:+UseParallelOldGC

  • -XX:UseParallelOldGC 配置老年代并行收集器 jdk6.0支持老年代并行收集

java -Xmx3500 -Xms3500 -Xmn2g -Xss128k -XX:UseParallelGC -XX:MaxGCPauseMillis=100

  • -XX:MaxGCPauseMillis=100 设置年轻代回收时长,超过jvm自动扩大年轻代

-XX:UseAdaptiveSizePolicy =100 设置这个系统会自动选择幸存者区比例,以达到系统目标规定的最低响应和收集频率

 

响应时间优先并发收集器

并发主要解决响应时间,防止停顿时间 

CMS 并发标记清理收集器

CMS  (-XX:UseConcMarkSweepGC ) 收集器在老年代使用,专门收集主要回收中不可达的老年对象,与应用程序,并发执行,在老年代一直有足够的空间保证不会发生年轻代复制过来失败

java -Xmx3550 -Xms3550 -Xmn2g -Xss128k -XX:ParallelGCThreaes=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

  1. -XX:+UseConcMarkSweepGC:设置老年代并发收集器
  2. -XX:+UseParNewGC: 设置年轻代并行收集器,可以在CMS 收集器同事使用 jkd5.0以上jvm 会更具系统自动配置,无需手动配置。

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFULLGCsBeforCompaction=5 -XX:+UseCMSCompactAtFullCollection

  • -XX:CMSFULLGCsBeforCompaction=5:由于并发收集器运行久了后会产生碎片,使的运行效率降低,这个值是设置运行多少次空间进行整理
  •  -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片。

 

配置汇总一下

  • -XX:+CMSIncrementalMode:设置为增量模式。适合 单个cpu

  • -XX:ParallelGCThreads=n 设置年轻代并发线程数量 收集器

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

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

  • -XX:+PrintGC

  • -XX:+PrintGCDetails

  • -XX:+PrintGCTimeStamps

  • -Xloggc:filename

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

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

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

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

  • -Xms:初始堆大小

  • -Xmx:最大堆大小

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

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

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

 

 

 

 

 

 

 

ok

 

 

 

 

 

 

 

 

 

 

 

 

持续更新