JVM1.8分代的理论基础和简单测试

news2025/2/24 14:34:29

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:

  1. 了解大厂经验
  2. 拥有和大厂相匹配的技术等

希望看什么,评论或者私信告诉我!

文章目录

  • 一、前言
  • 二、JVM 分代
    • 2.1 JVM 中对象生命周期分布
    • 2.2 JVM 分代图
    • 2.3 特殊情况
      • G1收集器内存分代
      • Parallel Collector 分代
  • 三、GC测试
    • 3.1 查看 JVM 模型配置
    • 3.2 代码测试
    • 3.3 GC 日志解释
  • 四、总结


一、前言

写过 java 的小伙伴肯定都知道 JVM 分为年轻代、永久代,但为什么这么分,有没有什么理论基础呢?

二、JVM 分代

2.1 JVM 中对象生命周期分布

经过对大量实际应用程序的观察和分析,得出如下图:

图片.png

x 轴表示对象在生命周期内,分配的字节数。 y 轴上表示相应生命周期内的对象占用的总字节数。左边的尖峰代表分配后不久可以回收的对象。蓝色区域表示对象生命周期的典型分布。所以可以得出如下结论:

  1. 大多数对象的生命周期很短暂:在许多应用程序中,绝大多数对象的生命周期都非常短暂,即它们很快就会变成垃圾,被回收掉
  2. 少数对象的生命周期较长:虽然大部分对象很快就会被回收,但也有一小部分对象的生命周期比较长,它们可能会存活很长时间

为了优化上述的两点,在内存管理方面,JVM按代进行管理,利用内存池保存不同年龄的对象。每当某一代充满时,会触发垃圾收集操作。

大多数对象被分配到年轻代,其中绝大多数对象最终在这一代消亡。当年轻代达到容量时,会触发垃圾收集,只针对年轻代进行垃圾回收;而其他代中的垃圾暂不处理。在每次次要收集时,一部分幸存对象会被移至永久代。永久代最终也会填满,需要对整个堆进行回收,持续的时间通常年轻代长,因为牵扯的对象数量更多。

2.2 JVM 分代图

JVM默认的分代图,需要注意的是排除:Parallel Collector and G1回收算法

图片.png

  1. 在初始化时,虚拟地保留最大地址空间,但除非需要,否则不会分配给物理内存。为对象内存保留的完整地址空间可以分为年轻代和终身代。
  2. 年轻代由 eden 和两个 survivor 空间组成。大多数对象最初是在 eden 中分配的。一个survivor 空间在任何时候都是空的,并且作为 eden 中任何存活对象的目的地;另一个 survivor 空间是下一次复制收集期间的目的地。对象以这种方式在幸存者空间之间复制,直到它们足够老而可以被保留(复制到终身代)。

2.3 特殊情况

G1收集器内存分代

  1. 不再明显的分代概念:与传统的分代收集器不同,G1收集器没有严格的年轻代和老年代的划分。它将整个堆分为多个大小相等的区域(Region),并根据垃圾收集的活动动态地划分为年轻代和老年代区域。
  2. 独特的回收方法:在G1中,每个区域都可以用作年轻代或老年代,因此没有严格意义上的固定分代。它会选择多个区域进行垃圾收集,并使用一种叫做“垃圾优先”(Garbage First)算法来进行整体的堆回收。

Parallel Collector 分代

在Parallel Collector中,与其他经典的垃圾收集器(如Serial收集器和CMS收集器)不同,它在新生代的设计中没有显式地使用Eden区和Survivor区的划分。而是将新生代划分为一部分专门用于存放对象的区域,这使得Parallel Collector更注重整个新生代的高效垃圾回收

三、GC测试

3.1 查看 JVM 模型配置

java -XX:+PrintCommandLineFlags -version

我这台机器的默认配置如下:

-XX:InitialHeapSize=264819584 -XX:MaxHeapSize=4237113344 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
openjdk version "1.8.0_332"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_332-b09)
OpenJDK 64-Bit Server VM (Temurin)(build 25.332-b09, mixed mode)

解释如下:

-   `-XX:InitialHeapSize=264819584`:设置 JVM 初始堆内存大小为大约 **252MB**。这是 JVM 启动时分配的最小堆内存量。
-   `-XX:MaxHeapSize=4237113344`:设置 JVM 最大堆内存大小为大约 **4040MB**(即约 **3.94GB**)。这是 JVM 堆内存能够增长到的最大限度。在运行过程中,如果堆内存需求增加,JVM 堆大小可以动态增长直至此上限。
-   `-XX:+PrintCommandLineFlags`:指示 JVM 在启动时打印出所有的命令行标志(参数),这有助于调试和记录当前虚拟机的配置状态。
-   `-XX:+UseCompressedClassPointers`:启用类指针的压缩。在 64 位 JVM 上,这可以减少类元数据占用的内存空间,从而降低内存消耗,并可能提升性能。
-   `-XX:+UseCompressedOops`:启用“普通对象指针(Ordinary Object Pointers)”的压缩。此设置减少了64位系统上对象引用的大小,从而减少了内存使用并且没有显著影响到性能。这是提升大内存Java应用性能的一项常用技术。
-   `-XX:-UseLargePagesIndividualAllocation`:禁止为每个大页面(Large Page)进行单独的分配。大页面技术通常用于提高大型应用的性能,通过减少页面表条目的数量来减少CPU缓存的压力,但需要操作系统的支持。这个参数指定了不使用单独分配大页的方式,这可能是因为配置了通用的大页支持或者没有需求使用该特性。
-   `-XX:+UseParallelGC`:启用 Parallel 垃圾收集器。Parallel 收集器是一个并行的新生代垃圾收集器,使用多线程来提高垃圾收集效率,主要目标是增加应用程序的吞吐量。

3.2 代码测试

public static void main(String[] args) {
    while (true){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ArrayList<Object> objects = new ArrayList<>(1024);
        for (int i = 0; i < 1024 * 10; i++) {
            objects.add(new Object[]{});
        }

    }
}

不断的创建 List,为了更快的观察到 GC 日志,我们设置

-Xmx80m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:./gc.log

解释如下:

-   `-Xmx20m`:设置了 Java 堆的最大内存为 **20MB**。这个参数限制了 Java 程序运行时最大可用的堆内存大小,超过这个大小后 JVM 将会抛出 OutOfMemoryError 错误。
-   `-verbose:gc`:启用了垃圾回收输出信息。当垃圾回收器执行垃圾回收时,会输出简要的垃圾收集情况,包括开始和结束的时间点。
-   `-XX:+PrintGCDetails`:详细输出垃圾收集的信息。这个参数会打印出关于每次垃圾收集的详细信息,包括各个区域的使用情况、垃圾回收时间、被收集对象等信息。
-   `-XX:+PrintGCDateStamps`:打印垃圾回收发生的日期时间戳。此参数会在详细的垃圾收集日志中包含日期时间信息,有助于更好地跟踪和分析垃圾回收的情况。
-   `-Xloggc:./gc.log`:将垃圾收集日志输出到指定的文件中,这里指定为当前目录下的 `gc.log` 文件。通过这个参数,JVM 会将详细的垃圾收集日志记录到指定文件中,可以用于后续分析和调试。

运行上述代码,可以看到 GC 日志如下:

OpenJDK 64-Bit Server VM (25.332-b09) for windows-amd64 JRE (1.8.0_332-b09), built on Apr 23 2022 01:25:28 by "jenkins" with MS VC++ 12.0 (VS2013)
Memory: 4k page, physical 16551224k(667012k free), swap 52371688k(14504324k free)
CommandLine flags: -XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
2024-05-21T20:05:55.659+0800: 8.192: [GC (Allocation Failure) [PSYoungGen: 5632K->510K(6144K)] 5632K->1384K(19968K), 0.0024955 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2024-05-21T20:06:15.807+0800: 28.340: [GC (Allocation Failure) [PSYoungGen: 6142K->488K(6144K)] 7016K->1369K(19968K), 0.0008134 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2024-05-21T20:06:34.936+0800: 47.468: [GC (Allocation Failure) [PSYoungGen: 6120K->502K(6144K)] 7001K->1440K(19968K), 0.0009532 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2024-05-21T20:06:55.174+0800: 67.706: [GC (Allocation Failure) [PSYoungGen: 6134K->504K(6144K)] 7072K->1449K(19968K), 0.0008710 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2024-05-21T20:07:14.356+0800: 86.888: [GC (Allocation Failure) [PSYoungGen: 6136K->492K(6144K)] 7081K->1486K(19968K), 0.0007995 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2024-05-21T20:07:33.536+0800: 106.068: [GC (Allocation Failure) [PSYoungGen: 6078K->486K(4096K)] 7072K->1496K(17920K), 0.0010000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2024-05-21T20:07:46.621+0800: 119.153: [GC (Allocation Failure) [PSYoungGen: 4070K->160K(5120K)] 5080K->1501K(18944K), 0.0004745 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

3.3 GC 日志解释

我们一块一块的解释:

OpenJDK 64-Bit Server VM (25.332-b09) for windows-amd64 JRE (1.8.0_332-b09), built on Apr 23 2022 01:25:28 by "jenkins" with MS VC++ 12.0 (VS2013)
这段 GC 日志提供了关于 JVM 的版本信息和构建详情,下面是对这部分日志的解释:

-   **OpenJDK 64-Bit Server VM (25.332-b09) for windows-amd64 JRE (1.8.0_332-b09)** :这部分说明了 JVM 的具体信息。其中:

    -   OpenJDK 64-Bit Server VM 表示这是一个64位的服务器端虚拟机。
    -   25.332-b09 是 JVM 的版本号,提供了关于编译版号的详细信息。
    -   windows-amd64 表示 JVM 运行在 Windows 系统的 64 位架构上。
    -   JRE (1.8.0_332-b09) 提供了 Java 运行时环境版本信息。

-   **Built on Apr 23 2022 01:25:28 by "jenkins" with MS VC++ 12.0 (VS2013)** :这部分提供了 JVM 构建的时间和工具信息。

    -   Built on Apr 23 2022 01:25:28 表示 JVM 是在 2022年4月23日凌晨01:25:28 构建的。
    -   by "jenkins" 表示使用 Jenkins 自动化工具构建。
    -   with MS VC++ 12.0 (VS2013) 表明使用 Microsoft Visual C++ 12.0 (VS2013) 编译器来构建 JVM。
Memory: 4k page, physical 16551224k(667012k free), swap 52371688k(14504324k free)
这段 GC 日志中提供了关于系统内存情况的信息,下面是对这段日志的解释:

-   **Memory: 4k page**:指定系统内存页的大小为 4KB。这表示系统在管理内存时使用 4KB 作为一页的基本单位。这是操作系统中很常见的内存页大小。
-   **physical 16551224k(667012k free)** :表示系统的物理内存情况。在括号内的部分是具体数值,16551224k 表示系统的物理内存总共为 16,551,224 KB(约 16.5 GB),其中 667,012 KB(约 667 MB)是可用的空闲内存。系统内存中可能包括用于程序运行和缓存的内存等。
-   **swap 52371688k(14504324k free)** :给出了系统的交换空间(swap space)情况。在括号内的部分表示具体数值,52371688k 表示总共的交换空间为 52,371,688 KB(约 52.4 GB),其中有 14,504,324 KB(约 14.5 GB)是可用的空闲交换空间。交换空间是硬盘上用来扩展物理内存的一部分,当物理内存不足时,操作系统会将部分数据从内存中交换到硬盘的交换分区(swap partition)中。
2024-05-21T20:07:46.621+0800: 119.153: [GC (Allocation Failure) [PSYoungGen: 4070K->160K(5120K)] 5080K->1501K(18944K), 0.0004745 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
这段 GC 日志提供了一次垃圾回收事件的详细信息,下面是对这条日志的解释:

-   **时间戳信息**:2024年5月21日,UTC+0800时区,具体时间为20:07:46.621。这个时间戳提供了垃圾回收事件发生的时间。

-   **持续时间信息**:从上次垃圾回收到本次垃圾回收经过了约119.153秒。

-   **GC事件**:这次垃圾回收事件是由“Allocation Failure”引起的,即由于在年轻代进行对象分配时失败触发了垃圾回收。

-   **PSYoungGen信息**:涉及的内存区域为 PSYoungGen(Parallel Scavenge算法的年轻代)。具体变化如下:

    -   在垃圾回收前,年轻代中的内存从4070KB减少到160KB。
    -   年轻代的总容量为5120KB,表示年轻代的总大小。

-   **整个堆内存信息**:整个堆的内存变化如下:

    -   在垃圾回收前,整个堆内存从5080KB减少到1501KB。
    -   整个堆的总容量为18944KB,表示整个堆的总大小。

-   **耗时信息**:垃圾回收过程耗时为0.0004745秒。

    -   user=0.00 表示用户态时间为0秒。
    -   sys=0.00 表示系统态时间为0秒。
    -   real=0.00 表示实际时间为0秒。

综合解释,这条 GC 日志记录了一次由“Allocation Failure”引发的垃圾回收事件,描述了年轻代和整个堆内存的变化情况,以及垃圾回收过程的耗时信息

四、总结

JVM的分代机制是为了优化内存管理,将内存分为年轻代和老年代,利用内存池保存不同年龄的对象。

大多数对象被分配到年轻代,其中绝大多数对象最终在这一代消亡。当年轻代达到容量时,会触发垃圾收集,只针对年轻代进行垃圾回收;而其他代中的垃圾暂不处理。在每次次要收集时,一部分幸存对象会被移至永久代。永久代最终也会填满,需要对整个堆进行回收,持续的时间通常年轻代长,因为牵扯的对象数量更多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1691247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redhat7.4部署MySQL-5.7.17搭建双主互为主从

一、准备工作 需要先准备已经搭建好的两台数据库&#xff0c;并且保证服务器之间网络是通的&#xff0c;3306端口可以相互访问。 二、修改两台数据库my.cnf 配置文件&#xff0c;将下列内容添加进去&#xff0c;放在 [mysqld] 下 我们暂定两台服务器为A服务和B服务&#xff…

分享一个用AI降本的思路,不懂代码也能上手

如何用AI解决实际的业务问题&#xff1f; 生财圈友我来利用ChatGPT做算法建模&#xff0c;每年为公司省下6万元。 今天他将分享通过ChatGPT进行数据分析的思路&#xff0c;从最开始定义问题到最终数据论证。 上手的实操过程门槛并不高&#xff0c;但可以实现把官方电商平台的…

ts 字符串不能做索引异常提示 type because expression of type ‘string‘

Element implicitly has an any type because expression of type string cant be used to index type 例子 let a{b:"1",c:"1" } var b"b"; let ca[b] let ca[b]就会爆这个错误&#xff0c;因为在编译器看来b是一个未知的东西&#xff0c;它不…

生物识别技术存在的问题及需要考虑的关键事项

微信关注公众号网络研究观获取更多。 对数字身份验证不太了解的人通常认为生物识别技术是我们所有身份验证问题的答案。 许多人认为身份验证的终极是面部识别&#xff0c;甚至可能是 DNA 分析。 生物识别技术&#xff08;例如指纹、面部、虹膜、视网膜、静脉、几何、语音、…

148.【Windows DOS命令脚本文件】

Window待处理脚本 (一)、批处理编程初步体验1.什么是批处理程序&#xff1f;(1).批处理程序的定义(2).如何编辑批处理程序 2.批处理程序可以做什么&#xff1f;(1).匹配规则删除文件(2).新建文件&#xff0c;日志等(3).创建计算机病毒等 3.一个基本的批处理文件(1).带盘符的输出…

Java_多线程

有了多线程&#xff0c;我们就可以让程序同时做多件事情 作用&#xff1a; 提高效率 应用场景&#xff1a; 只要想让多个事情同时运行就需要用到多线程 比如&#xff1a;软件中的耗时操作、所有的聊天软件、所有的服务器... 并发和并行 并发&#xff1a;在同一时刻&#xff0…

一文详解逻辑越权漏洞

1. 逻辑越权 1.1. 漏洞原理 逻辑越权漏洞就是当用户跳过自己的权限限制&#xff0c;去操作同等级用户或者上级用户。正常的情况下&#xff0c;当一个用户去访问某个资源的时候&#xff0c;首先需要去登录验证自己的权限&#xff0c;其次是对数据的查询&#xff0c;最后返回数…

2024年学浪视频怎么下载到手机相册

随着2024年的到来&#xff0c;学浪平台继续为广大学习者提供优质的在线教育资源。然而&#xff0c;如何将这些宝贵的视频内容下载到手机相册&#xff0c;方便随时离线观看呢&#xff1f;无论您是想在旅途中学习&#xff0c;还是希望在没有网络的情况下复习课程&#xff0c;本文…

Linux之单机项目部署

1、虚拟机&#xff08;VMware&#xff09;创建Linux系统 1.1、创建虚拟机 1.2、配置虚拟机IOS映射文件 1.3、虚拟机内部相关配置 等待加载即可&#xff0c;加载完后会弹出图形化界面&#xff0c;如图&#xff1a; 注意&#xff1a;一般我们做为管理员使用ROOT账号来操作&#x…

Java之SpringSecurity使用心得

文章目录 一、内存身份认证二、jdbc身份认证三、自定义登录页 一、内存身份认证 添加pom依赖 <!-- Spring Security提供的安全管理依赖启动器 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-s…

串口服务器在工业控制领域的应用:深度解析与前沿实践

在工业控制领域&#xff0c;随着技术的不断发展&#xff0c;传统的串口通信方式已经难以满足现代工业系统对高效、稳定、安全通信的需求。此时&#xff0c;串口服务器作为一种先进的通信技术解决方案&#xff0c;正在逐步改变工业控制领域的通信格局。本文将深度解析串口服务器…

第十届水利、土木工程国际学术会议暨工程安全与防灾论坛 (ICHCE ESDP 2024)

文章目录 一、会议详情二、重要信息三、会议简介四、组织单位五、出席嘉宾六、大会议程七、咨询 一、会议详情 二、重要信息 会议官网&#xff1a;www.ichce.org 大会时间&#xff1a;2024年8月9-11日 最后一轮截稿时间&#xff1a;2024年6月30日 报名截止时间&#xff1a;2…

得物小程序逆向+qt可视化(不含sku)

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

linux-配置服务器之间 ssh免密登录

前言 在管理多台Linux服务器时,为了方便操作和自动化任务,实现服务器之间的SSH免密登录是非常有必要的。SSH免密登录可以避免每次远程连接时输入密码,大大提高效率。本文将详细介绍SSH免密登录的原理和实现步骤。 一、原理解释 SSH免密登录的实现依赖于SSH密钥对,主要是利用…

为什么手机冬天续航短 – 锂电池的温度特性曲线

原文出自微信公众号【小小的电子之路】 相信大家都有这样的经历&#xff1a;手机的续航能力在寒冷的冬天会有一定程度的降低&#xff0c;有些手机甚至充不进去电。在这种情况下&#xff0c;有些人可能会在手机上贴一个暖宝宝。其实这个问题不止出现在手机上&#xff0c;大家如果…

Mybatis Cache(一)MybatisCache+Redis

前面提到了&#xff0c;使用mybatis cache&#xff0c;一般是结合redis使用。 一、demo 1、数据表 create table demo.t_address (id int auto_incrementprimary key,address_name varchar(200) null,address_code varchar(20) null,address_type int n…

Java进阶学习笔记4——Static应用知识:代码块

代码块&#xff1a; 代码块是类的五大成员之一&#xff08;成员变量、构造器、方法、代码块、内部类&#xff09;。 Java类生命周期&#xff1a;加载、验证、准备、初始化、卸载。 代码块分为两种&#xff1a; 静态代码块&#xff1a; 格式&#xff1a;static {} 特点&…

Linux--网络通信(一)概述

网络通信概述 网络通信本质上是一种进程间通信&#xff0c;是位于网络中不同主机上的进程之间的通信&#xff0c;属于 IPC 的一种&#xff0c; 通常称为 socket IPC。所以网络通信是为了解决在网络环境中&#xff0c;不同主机上的应用程序之间的通信问题。 大概可以分为三个层…

物联网应用开发--STM32与机智云通信(ESP8266 Wi-Fi+手机APP+LED+蜂鸣器+SHT20温湿度传感器)

实现目标 1、熟悉机智云平台&#xff0c;会下载APP 2、熟悉新云平台创建产品&#xff0c;项目虚拟调试 3、掌握云平台生成MCU代码&#xff0c;并移植。机智云透传固件的下载 4、具体目标&#xff1a;&#xff08;1&#xff09;注册机智云平台&#xff1b;&#xff08;2&…

转行3年涨薪300%,我总结了一套产品经理快速入门指南!

想转行的产品小白&#xff0c;初期一定会遇到这个问题——我要如何 0 基础转行产品经理&#xff1f; 要想 0 基础快速转行产品经理&#xff0c;我通过个人实践总结了 5 个关键点&#xff0c;可以参考。 一、熟悉产品经理的工作全流程 转行的产品小白&#xff0c;首先要建立产…