首页 > 编程知识 正文

jvm有哪些垃圾回收算法,jvm性能调优都做了什么

时间:2023-05-03 09:07:31 阅读:16434 作者:753

一、Java JVM组成1、简介: JVM、Java语言独有的垃圾回收处理机制。 个人汇总垃圾回收图例:

1.1由JVM组成的垃圾收集器分为堆栈、Heap、方法区域、PC注册程序计数器和本机方法堆栈

、Class Loader类加载器和本机接口组成。

1.2堆栈也称为堆栈内存,负责运行Java程序的是在创建线程时创建的,其生命周期是跟随线程的生命周期。 线程结束后,堆栈内存也被释放。 对堆栈来说没有垃圾回收问题,线程结束时该堆栈将溢出。 只要生命周期和线程匹配,线程就是专用的。 基本类型的变量和对象的引用变量被分配给函数的堆栈内存。

Java方法执行包含局部变量、操作数堆栈、动态链接和方法出口等信息的内存模型。

1、堆栈存储是什么?

堆栈帧主要存储三种类型的数据。 局部变量(Local Variables ) :输入和输出参数以及方法中的变量; 堆栈操作(操作堆栈) :堆栈,记录进入堆栈的操作; 堆栈数据(Frame Data ) :包括类文件、方法等。

2、叠运行原理

堆栈中的所有数据都以堆栈帧(Stack Frame )的形式存在,堆栈帧是存储器块、数据集、关于方法(Method )和运行时数据的数据集,以及方法a a方法调用b方法来推入堆栈帧F2,生成堆栈,于是堆栈帧F3也被推入堆栈,……执行完成后,首先推出F3堆栈帧,接着推出F2堆栈帧,接着是fff 3堆栈帧

堆栈溢出的原因

一)、是否有递归调用

二)、是否有大量循环或死亡循环

三)全局变量是否过多

四)、数组、列表、映射数据是否过大

堆栈类似于弹匣。 先进先出、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次后到达养老区。 养老区空间不足时,会进行马焦格控制,也称为全格控制,全格控制只发生在养老区。 如果完全通用汽车运行不足以放置养老区中从前面移动过来的对象,则会报告错误。 Java.lang.out of memory error 3360 javaheapspace

如果发生Java.lang.out of memory error 3360 javaheapspace异常,则说明Java虚拟机的堆内存不足。 原因有两个:

)1) Java虚拟机堆内存设置不足,可以通过-Xms、-Xmx参数进行调整。

)在代码中创建了大量大对象,而且垃圾收集器没有收集这些对象的时间很长) )存在引用对象)。

堆栈溢出代码String str='www.niubi.com '; while(true ) str=strnew Random ).nextint ) 8888888 ) newrandom ).nextint (99999999 ); (7.2养老区

养老区用于存储从常规长椅区筛选出的JAVA对象,常见的游泳池对象活跃在该区域,很少发生垃圾回收

示例: byte [ ] b=new byte [ 1024 x 1024 x 1024 ];

永久空间在逻辑上是堆内存,实际上不是堆。 1.7前,他用于存储运行Java程序所需的jar包

Book b1=new Book (;

Book b1位于堆栈中,并与new Book (; 在山上的伊甸园里

1.8用元空间替换了永久区

永久空间非堆内存

永久空间—启动常规存储程序时需要加载的jar包

永久区域已满时,发生Java.lang.out of memory:permgenspace异常(永久内存溢出)

7.3永久区

永久存储区是存储JDK自身拥有的Class、Interface元数据的驻留内存区域。 这意味着它包含运行时所需的类信息,并且垃圾收集器不会回收加载到此区域的数据。 关闭JVM将释放此空间占用的内存。

如果ja出现了

va.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五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。