Java JVM 垃圾回收 垃圾回收器 jvm调优

一、Java JVM 组成

1、概述:JVM,Java语言自己的垃圾回收处理机制。个人总结 垃圾回收图例:

在这里插入图片描述

1.1JVM组成

垃圾回收器分为Stack(栈)、Heap(堆)、Method Area(本地方法区)、PC Register 程序计数器、Native Method Stack 本地方法栈
、Class Loader类加载器、Native Interface 本地接口组成。

1.2 Stack 栈是什么

栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的。基本类型的变量和对象的引用变量都是在函数的栈内存中分配。
Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息。
1、栈存储什么?
栈帧中主要保存3 类数据: 本地变量(Local Variables):输入参数和输出参数以及方法内的变量; 栈操作(Operand Stack):记录出栈、入栈的操作; 栈帧数据(Frame Data):包括类文件、方法等等。
2、栈运行原理
栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧 F1,并被压入到栈中, A方法又调用了 B方法,于是产生栈帧 F2 也被压入栈, B方法又调用了 C方法,于是产生栈帧 F3 也被压入栈, …… 执行完毕后,先弹出F3栈帧,再弹出F2栈帧,再弹出F1栈帧…… 遵循“先进后出”/“后进先出”原则。
栈溢出的原因
一)、是否有递归调用
二)、是否有大量循环或死循环
三)、全局变量是否过多
四)、 数组、List、map数据是否过大
栈类似于弹夹,先进后出,8中数据类型,和引用数据类型都在栈中
常见异常java.lang.stackOverFlowError,栈内存溢出,例方法中不停的调用自己,导致溢出

1.2 Heap 堆

线程共享
一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三部分:
Young Generation Space 新生区 Young
Tenure generation space 养老区 Old
Permanent Space 永久存储区 Perm
堆模型
在这里插入图片描述

jdk1.7:
堆内存分布,分为新生区,养老区,永久区。
其中新生区分为伊甸区,幸存0,幸存1,所以新new的对象都放在伊甸区,如果伊甸区空间存储到达70%,jvm会进行minor GC,清理伊甸区并将留下的对方转移到幸存0,minor GC仅发生在伊甸区。
每次发生minor GC之后,将剩下的对象依次往后挪,即伊甸区到幸存0到幸存1,15次后到养老区。当养老区空间不足时,会进行majorGC,也称为full gc,full GC仅发生在养老区。当进行full gc后养老区的空间仍然不足以放前面挪过来的对象,就会报错:java.lang.OutOfMemoryError:java heap space
如果出现java.lang.OutOfMemoryError: Java heap space异常,说明Java虚拟机的堆内存不够。原因有二:
(1)Java虚拟机的堆内存设置不够,可以通过参数-Xms、-Xmx来调整。
(2)代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)。

堆内存溢出代码
String str = "www.niubi.com" ;
while(true) {
str += str + new Random().nextInt(88888888) +
 new Random().nextInt(999999999) ;
}

7.2 养老区
养老区用于保存从新生区筛选出来的 JAVA 对象,一般池对象都在这个区域活跃,很少发生垃圾回收

例子:byte[] b=new byte[1024x1024x1024];
永久区逻辑上属于堆内存,实际上非堆(1.7前),他用于存放Java程序运行所需要的jar包
Book b1=new Book();
Book b1在栈中,new Book();在堆的伊甸园区
1.8将永久区换成了元空间
永久区非堆内存
永久区:一般存放程序启动需要加载的jar包
当永久区被占满只后会爆出java.lang.OutofMemory:PermGen space 异常(永久代内存溢出)
7.3 永久区
永久存储区是一个常驻内存区域,用于存放JDK自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。
如果出现java.lang.OutOfMemoryError: PermGen space,说明是Java虚拟机对永久代Perm内存设置不够。一般出现这种情况,都是程序启动需要加载大量的第三方jar包。
例如:在一个Tomcat下部署了太多的应用。或者大量动态反射生成的类不断被加载,最终导致Perm区被占满。
Jdk1.6及之前: 常量池分配在永久代
Jdk1.7: 有,但已经逐步“去永久代”
Jdk1.8及之后: 无
jdk1.7
在这里插入图片描述
jdk1.8
JDK 1.8之后将最初的永久代取消了,由元空间取代。
目的:将HotSpot与JRockit两个虚拟机标准
在这里插入图片描述

1.3 Method Area 方法区

方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。简单说,所有定义的方法的信息都保存在该区域,此区属于共享区间。 静态变量+常量+类信息+运行时常量池存在方法区中,实例变量存在堆内存中

1.4 PC Register 程序计数器

每个线程都有一个程序计数器,就是一个指针,指向方法区中的方法字节码(下一个将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。

1.5 Native Method Stack 本地方法栈

线程私有的,它的具体做法是 Native Method Stack中登记native方法,在Execution Engine 执行时加载native libraies。

1.6 Native Interface 本地接口

本地接口的作用是融合不同的编程语言为 Java 所用,它的初衷是融合 C/C++程序,Java 诞生的时候是 C/C++横行的时候,要想立足,必须有调用 C/C++程序,于是就在内存中专门开辟了一块区域处理标记为 native的代码,它的具体做法是 Native Method Stack中登记 native方法,在Execution Engine 执行时加载native libraies。 目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过 Java程序驱动打印机,或者 Java系统管理生产设备,在企业级应用中已经比较少见。 因为现在的异构领域间的通信很发达,比如可以使用 Socket 通信,也可以使用 Web Service等等,不多做介绍。

1.7 Class Loader类加载器

负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定

二、JVM垃圾回收器及调优

1、垃圾回收器

结构图
在这里插入图片描述
1、Serial串行回收,2、Parallel并行回收3、CMS并发标记清除,4、G1,java10以前的
在这里插入图片描述

1.1 Serial串行回收

垃圾回收器
串行Serial
到达峰值,启动gc线程,清除继续运行,程序–>GC–>程序
在这里插入图片描述

1.2 Parallel并行回收

多个垃圾回收线程,程序–>多个GC–>程序
在这里插入图片描述

1.3 CMS并发标记清除,并发垃圾回收

不会完全暂停,并发更为复杂,但是会占用应用cpu
在这里插入图片描述

1.4 G1垃圾回收,1.8以后,java11–zgc

在这里插入图片描述
默认使用的是并行垃圾回收
串行并行
在这里插入图片描述

2、垃圾回收参数及区域

7种gc,串行gc(新生区),并行gc(新生区),ParNewGc(新生区),ParallelGC(新生区),ParalleloldGC(养老区)CMSGC(并发标记清除GC)(养老区)
垃圾回收器具体实现GC算法并实现内存回收

2.1 新生代,串行serial/serial Copy

古老稳定,效率高,一个线程回收,会暂停其他的线程
-XX:+UseSerialGC,开启,开启后会使用:Serial(新生区)+Serial Old(Old区)的收集器组合
表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记整理算法
初始空间 最大空间 打印参数细节 查看默认使用GC
-Xmx10M -Xmx10m
-XX:+PrintGCDetails
-XX:+PrintCommandLineFlags
-XX:+UseSerialGC

2.2 并行ParNew

并行收集器,多个线程进行垃圾回收,也会暂停线程,新生代并行多线程配合老年代的CMSGC工作
开启参数:-XX:+UseParNewGC 开启后使用ParNew+Serial Old的收集器(不再推荐),
新生代使用复制,老年代使用标记整理

-Xmx10M -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParNewGC
-XX:ParallelGCThreads
限制线程数,默认开启CPU数目相同的线程数

ParallelScavenge 并行回收gc算法,默认的
和老年代一样开启并行回收,吞吐量优先收集器
可控吞吐量,运行用户代码时间/(运行用户代码时间+垃圾收集时间)

开启参数:-XX:+UseParallelGC,-XX:+UseParallelOldGC(互相激活)
cpu>8 N=5/8 cpu<8 N=实际个数

-Xmx10M -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelGC
-Xmx10M -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelOldGC

2.3 养老区CMS并发标记清除:

CMS并发标记清除ConcMarkSweepGC:获取最短回收停顿时间为目标的收集器
并发收集低停顿
节约内存空间,会有内存碎片
开启:-XX:+UseConcMarkSweepGC开启后会将UseParallelGC打开
开启后会用

1、初始标记,标记下关联对象,需要暂停所有的工作线程
2、并发标记,和用户线程一起,标记全部对象
3、重新标记,CMS remark ,标记产生变动的对象,需要暂停
4、并发清除,和用户线程一起,直接清理对象,不需要暂停
在这里插入图片描述
优点:并发收集低停顿
缺点:
1、并发执行对cpu的压力
2、采用的标记清除算法会导致大量的碎片

参数配置
-Xmx10M -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseConcMarkSweepGC

Serial Old
在这里插入图片描述

2.4 G1垃圾回收

面向服务端的垃圾收集
-Xmx10M -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseG1GC
在这里插入图片描述
在这里插入图片描述
不会产生内存碎片,添加了预测机制,用户可以指定期望停顿时间
Cms垃圾收集器虽然减少了暂停应用的运行时间,但是它还是存在着内存碎片问题
在这里插入图片描述
特点
在这里插入图片描述

3、G1底层原理

Region区域化垃圾收集器,化整为零,避免全内存扫描,只需按照区域进行扫描
将新生区养老区编为不连续的内存区域,避免了全内存区gc操作,将整个内存区域分成大小相同的子区域,JVM启动时自动设置这些子区域的大小,G1只要求对象的存储逻辑连续,可以按需在新生代和老年代切换
启动时可以通过参数 -XX:G1HeapRegionSize=n可指定分区大小(1-32mb),为2的幂,默认将整堆划分为2048个分区,能够支持最大内存,32*2048=65536MB=64GB内存
在这里插入图片描述
在这里插入图片描述

4、大对象

在这里插入图片描述回收步骤:
针对伊甸园区:小区域收集+形成连续的内存块,避免内存碎片
在这里插入图片描述
4步过程:
初始标记:只标记GC Roots能直接关联到对象
并发标记:进行Gc Roots Tracing的过程
最终标记:修正并发标记期间,因程序运行导致标记发生变化的那一部分对象
筛选回收,根据时间来进行价值最大化的回收
在这里插入图片描述

5、配置G1

三步:开始G1+设置最大内存+设置最大停顿时间毫秒
-XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=100
G1跟Cms的优势:
G1没有内存碎片,可以精确的控制停顿时间

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会改bug的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值