当前位置: 首页 > news >正文

JAVA开发(JAVA垃圾回收的几种常见算法)

JAVA GC 是JAVA虚拟机中的一个系统或者说是一个服务,专门是用于内存回收,交还给虚拟机的功能。

JAVA语言相对其他语言除了跨平台性,还有一个最重要的功能是JAVA语言封装了对内存的自动回收。俗称垃圾回收器。所以有时候我们不得不承认,我们写的每一行JAVA代码都是垃圾!

那么JAVA虚拟机中,对应内存的回收常见的有哪些的呢。 我知道的有:

标记清除法、标记整理算法、复制清除、分代收集;其中最常用的是分代收集。

标记清除法:

示意图:

初始状态是一块空白未被使用的内存。java语言类中声明的对象运行,在堆中使用内存块。红的和绿的部分。

过了一段时间,垃圾回收器工作,检测哪些对象在使用,哪些对象不使用了进行标记。绿色部分为存活对象,红色部分为被标记。

然后将红色可回收的对象,清除释放内存。

优点:效率很高,快速。

缺点:使内存碎片化,不方便分配大内存。

标记整理算法:

示意图:

 标记整理法比标记法多做一步工作,就是标记清除后,对碎片进行整理,移动。空出更大的内存块。

优点:尽可能空闲出较大块的内存块。

缺点:垃圾回收器比较忙碌。在移动内存对象过程中,消耗性能和效率。

复制清除:

示意图:

  
复制清除法可用内存一分为二,每次只用一块,当这一块内存不够用时,便触发 GC,将当前存活对象复制(Copy)到另一块上,以此往复 Java 对象的存活时间极短。
Java 对象高达 98% 是朝生夕死的,这也意味着每次 GC 可以回收大部分的内存,需要复制的数据量也很小,这样它的执行效率就会很高。

优点:效率高

缺点:只能使用50%的内存。

分代收集法:

示意图:

 分代收集法:

根据对象一般都是先在 Eden区创建
当Eden区满,触发 Young GC,此时将 Eden中还存活的对象复制到 S0中,并清空 Eden区后继续为新的对象分配内存
当Eden区再次满后,触发又一次的 Young GC,此时会将 Eden和S0中存活的对象复制到 S1中,然后清空Eden和S0后继续为新的对象分配内存
每经过一次 Young GC,存活下来的对象都会将自己存活次数加1,当达到一定次数后,会随着一次 Young GC 晋升到 Old区
Old区也会在合适的时机进行自己的 GC。

新生代(Young generation)
绝大多数新创建的对象都会被分配到这里,这个区域触发的垃圾回收称之为:Minor GC 。

空间结构:
默认情况下,新生代(Young generation)、老年代(Old generation)所占空间比例为 1 : 2 。
它被分成三个空间:
· 1个伊甸园空间(Eden)
· 2个幸存者空间(Fron Survivor、To Survivor)
默认情况下,新生代空间的分配:Eden : Fron : To = 8 : 1 : 1
为什么要这样的布局?是因为新生代里的对象绝大多数是朝生夕死的,非常适合使用标记-复制算法,后面的回收算法章节会详细说。

新生代GC收集的执行顺序如下:
1、绝大多数新创建的对象会存放在伊甸园空间(Eden)。
2、在伊甸园空间执行第 1 次GC(Minor GC)之后,存活的对象被移动到其中一个幸存者空间(Survivor)。
3、此后每次 Minor GC,都会将 Eden 和 使用中的Survivor 区域中存活的对象,一次性复制到另一块空闲中的Survivor区,然后直接清理 Eden 和 使用过的那块Survivor 空间。
4、从以上空间分配我们知道,Survivor区内存占比很小,当空闲中的Survivor空间不够存放活下来的对象时,这些对象会通过分配担保机制直接进入老年代。
5、在以上步骤中重复N次(N = MaxTenuringThreshold(年龄阀值设定,默认15))依然存活的对象,就会被移动到老年代。
从上面的步骤可以发现,两个幸存者空间,必须有一个是保持空的。
我们需要重点记住的是,新创建的对象,是保存在伊甸园空间的(Eden)。那些经历多次GC依然存活的对象会经由幸存者空间(Survivor)转存到老年代空间(Old generation)。
也有例外出现,对于一些大的对象(指需要占用大量连续内存空间的对象)则直接进入到老年代。
Java提供了 -XX:PretenureSizeThreshold 来指定对象大于这个值,直接分配到老年代。


老年代(Old generation)
对象在新生代周期中存活了下来的,会被拷贝到这里。通常情况下这个区域分配的空间要比新生代多。正是由于对象经历的GC次数越多越难回收,加上相对大的空间,发生在老年代的GC次数要比新生代少得多。这个区域触发的垃圾回收称之为:Major GC 或者 Full GC
老年代空间的构成其实很简单,它不像新生代空间那样划分为几个区域,它只有一个区域,里面存储的对象并不像新生代空间里绝大部分都是朝闻道,夕死矣。这里的对象几乎都是从Survivor 空间中熬过来的,它们绝不会轻易狗带。因此,Major GC 或 Full GC 发生的次数不会有 Minor GC 那么频繁。
2、老年代使用的是标记-整理算法,清理完成内存后,还得把存活的对象重新排序整理成连续的空间,成本更高。

优点:低频率触发GC,更好的触发内存回收。

下面才是重点:知道了原理那怎么使用或者制定使用GC。java虚拟机中有很多种GC,我们可以通过配置指定,语法:

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

             -Xmx3800m:最大堆大小

      -Xms3800m:初始堆大小,此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

      -Xmn2g: 设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

      -Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,

      不能无限生成,经验值在3000~5000左右。

      -XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即该配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。

      -XX:ParallelGCThreans = 20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值的配置最好与处理器数目相等。

--------------------------------------------------------------------------------------------------------------------------

    常见配置汇总

    -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况

    -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数

    -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数

    -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:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

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

    堆设置

    收集器设置

    垃圾回收统计信息

    并行收集器设置

    并发收集器设置

  调优总结

    -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩

    -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩

    -XX:MaxHeapFreeRatio=30

    响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时

  间。最优化的方案,一般需要参考以下数据获得:减少年轻代和年老代花费的时间,一般会提高应用的效率

    吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。

    并发垃圾收集信息

    持久代并发收集次数

    传统GC信息

    花在年轻代和年老代回收上的时间比例

    响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。

    吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。

    年轻代大小选择

    年老代大小选择

    较小堆引起的碎片问题

      因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:

    -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩

    -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩

    -XX:MaxHeapFreeRatio=30

相关文章:

JAVA开发(JAVA垃圾回收的几种常见算法)

JAVA GC 是JAVA虚拟机中的一个系统或者说是一个服务,专门是用于内存回收,交还给虚拟机的功能。 JAVA语言相对其他语言除了跨平台性,还有一个最重要的功能是JAVA语言封装了对内存的自动回收。俗称垃圾回收器。所以有时候我们不得不承认&#…...

你还不会用CAD一键布置停车位?赶紧学起来!

在设计CAD建筑图的过程中,你还在一个一个地画停车位吗?那未免也太低效了吧!今天,小编用浩辰CAD建筑软件来教大家一键布置停车位,赶紧学起来吧! 浩辰CAD建筑软件是行业应用最广泛的创新型建筑设计专业软件&…...

【MySQL之MySQL底层分析篇】系统学习MySQL,从应用SQL语法到底层知识讲解,这将是你见过最完成的知识体系

文章目录MySQL体系结构MySQL存储结构(以InnoDB为例)MySQL执行流程(以InnoDB为例)1. 数据写入原理2. 数据查询原理MySQL存储引擎1. 为什么需要不同的存储引擎2. 如何为数据指定不同的存储引擎,数据粒度又是多少3. MySQL…...

单核CPU是否有线程可见性问题?

本文仅是本人对问题的思考记录,并没有实操验证,有误请大家评论指出。 今天见到了一个经典的问题,单核CPU是否有线程可见性问题,学完操作系统应该可以直接回答,不会有线程安全问题。但如果结合JVM虚拟机来进行分析&…...

MyBatis 架构介绍

MyBatis 架构介绍MyBatis 架构图MyBatis 所解决的 JDBC 中存在的问题引用MyBatis 架构图 mybatis 配置:mybatis-config.xml,此文件作为 mybatis 的全局配置文件,配置了 mybatis 的运行环境等信息。另一个 mapper.xml 文件即 sql 映射文件,文件…...

加密算法---RSA 非对称加密原理及使用

加密算法---RSA 非对称加密原理及使用一 非对称加密原理介绍二 加密解密测试2.1 加密解密工具类2.2 测试一 非对称加密原理介绍 非对称加密算法中,有两个密钥:公钥和私钥。它们是一对,如果用公钥进行加密,只有用对应的私钥才能解…...

MySQL-查询语句

数据库管理系统的一个最重要的功能就是数据查询,数据查询不应只是简单查询数据库中存储的数据,还应该根据需要对数据进行筛选,以及确定数据以什么样的格式显示。MySQL提供了功能强大、灵活的语句来实现这些操作。下面是通过help帮助查看到的s…...

【算法】【数组与矩阵模块】求数组中需要排序的最短子数组长度

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 问题介绍 …...

centos安装Anaconda3

目录一、参考二、Anaconda简介1、用途2、关于anaconda三、下载安装1、下载2、安装anaconda3、配置环境遍历4、测试配置结果5、设置显示前缀一、参考 在centos上安装Anaconda 最新Anaconda3的安装配置及使用教程(附图文) 二、Anaconda简介 一句话&…...

【微信小程序】-- WXML 模板语法 - 列表渲染 -- wx:for wx:key(十二)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...

【Linux】Linux中gcc/g++的使用

本期主题:程序的编译过程和gcc/g的使用博客主页:小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限,出现错误希望大家不吝赐🍁 1.背景知识 预处理(进行宏替换,去注释,头文件的…...

【Spring Cloud Alibaba】(五)Dubbo启动报错?一直重连报错?你值得学习的是排查问题的方法

系列目录 【Spring Cloud Alibaba】(一)微服务介绍 及 Nacos注册中心实战 【Spring Cloud Alibaba】(二)微服务调用组件Feign原理实战 【Spring Cloud Alibaba】(三)OpenFeign扩展点实战 源码详解 【Spri…...

adb命令的使用

命令 连接机顶盒 adb connect [机顶盒ip]查看已连接设备 adb devices断开某个机顶盒的连接 adb disconnect [机顶盒ip] or adb disconnect [虚拟机名称]断开所有设备连接 adb disconnect获取 root 权限 adb root挂载文件系统 adb remount当想往移动设备端 push 文件时显…...

springBoot自定义参数类型转换器

springBoot允许用户自定义转换器,以处理自定义请求参数协议。 方式一:通过实现接口:WebMvcConfigurer 并重写方法的形式。 Configuration public class BootConfig implements WebMvcConfigurer {/*** 自定义参数转换*/Overridepublic voi…...

OA系统在企业中的应用你知道哪些?

随着人工智能技术的不断发展,企业中的OA系统(Office Automation System)正在逐渐得到广泛应用。OA系统是一种集成了多种功能的信息化工具,能够帮助企业实现办公自动化、信息管理、决策支持等多种功能。本文将从OA系统在企业中的应…...

JAVA中,ArrayList 的扩容机制,含案例

JAVA中,ArrayList 的扩容机制,含案例 在 Java 中,ArrayList 是一个动态数组,它可以根据需要自动增长。当 ArrayList 中的元素数量超过其初始容量时,它会重新分配一个更大的内部数组,然后将现有元素复制到新…...

供应链的有效管理,分析指标有哪些

对于企业而言,供应链是一个很复杂的、体系化的生态系统,从原材料、到供应商、到生产、仓库、物流,最后到达经销商或者最终客户那里,这个链条很长。相关的分析指标也有很多,在这些指标里面也有非常多可以扩展、延申的内…...

嵌入式环境配置—VMware 软件安装和虚拟机的创建

目录 一、VMware软件的安装 二、虚拟机的创建 三、Linux操作系统的安装 VMware软件的安装 为什么要虚拟机? 嵌入式Linux开发需要在Linux系统下进行,我们选择了Ubuntu。 1.双系统安装 有问题,一次只能使用一个系统。Ubuntu基本只做编译用。需求&…...

阿里前端二面经典手写面试题汇总

实现类的继承 实现类的继承-简版 类的继承在几年前是重点内容,有n种继承方式各有优劣,es6普及后越来越不重要,那么多种写法有点『回字有四样写法』的意思,如果还想深入理解的去看红宝书即可,我们目前只实现一种最理想…...

【Eye】Fake News Reading on Social Media: An Eye-tracking Study

Fake News Reading on Social Media: An Eye-tracking Study Abstract 在网上传播假新闻(以及一般的虚假信息)最近被认为是威胁整个社会的一个主要问题。这种传播在很大程度上是由于新的媒体形式,即社交网络和在线媒体网站。研究人员和从业…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...

js 设置3秒后执行

如何在JavaScript中延迟3秒执行操作 在JavaScript中&#xff0c;要设置一个操作在指定延迟后&#xff08;例如3秒&#xff09;执行&#xff0c;可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法&#xff0c;它接受两个参数&#xff1a; 要执行的函数&…...