为什么用元空间替代永久代?

为什么用元空间替代永久代?永久代和元空间都是 HotSpot 虚拟机中的概念,HotSpot 虚拟机是 Sun JDK 和 Open JDK 中自带的虚拟机,也是目前使用范围最广泛的 Java 虚拟机,当我们提到虚拟机时,大概

永久代和元空间都是 HotSpot 虚拟机中的概念,HotSpot 虚拟机是 Sun JDK 和 Open JDK 中自带的虚拟机,也是目前使用范围最广泛的 Java 虚拟机,当我们提到虚拟机时,大概率指的就是 HotSpot 虚拟机。

但从《Java 虚拟机规范》的层面来说,并没有所谓的“永久代”和“元空间”等区域,详见官方文档:docs.oracle.com/javase/spec…。《Java 虚拟机规范》只是规定了一个区域叫“方法区(Method Area)”,而 “永久代”和“元空间”是 HotSpot 虚拟机在不同的 JDK 版本下,对方法区的具体实现而已。这就好像,世界羽协规定羽毛球比赛必须要使用羽毛球拍(方法区),而中国羽毛球运动员,第一年使用的是红双喜牌的羽毛球拍(永久代),第二年使用的是李宁牌羽毛球拍(元空间)一样。

那么问题来了,永久代为什么被元空间给替代了?

1.官方答案

关于这个问题,官方在 JEP 122: Remove the Permanent Generation(移除永久代)中给出了答案,原文内容如下:

Motivation(动机) This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.

以上内容翻译成中文大意是:

这是 JRockit 虚拟机和 HotSpot 虚拟机融合工作的一部分。JRockit 客户不需要配置永久层代(因为 JRockit 没有永久代),所以要移除永久代。

JRockit 是 Java 官方收购的一家号称史上运行最快的 Java 虚拟机厂商,之后 Java 官方在 JDK 8 时将 JRockit 虚拟机和 HotSpot 虚拟机进行了整合。

PS:JEP 是 JDK Enhancement Proposal 的缩写,翻译成中文是 JDK 改进提案。你也可以把它理解为 JDK 的更新文档。

通过官方的描述,我们似乎找到了答案,也就是说,之所以要取消“永久代”是因为 Java 官方收购了 JRockit,之后在将 JRockit 和 HotSpot 进行整合时,因为 JRockit 中没有“永久代”,所以把永久代给移除了

PS:上面的那段描述好像说的已经很清楚了,但又好像什么也没说。这就好比,我问你“为什么要买车?”,你说“别人都买车了,所以我要买车”,但为什么别人要买车?

2.背后的原因

上述给出了移除永久代的回答,但却没有给出背后的原因,那接下来我们就来讨论一下,为什么要移除永久代?以及为什么要有元空间?

2.1 降低 OOM

当使用永久代实现方法区时,永久代的最大容量受制于 PermSize 和 MaxPermSize 参数设置的大小,而这两个参数的大小又很难确定,因为在程序运行时需要加载多少类是很难估算的,如果这两个参数设置的过小就会频繁的触发 FullGC 和导致 OOM(Out of Memory,内存溢出)。

但是,当使用元空间替代了永久代之后,出现 OOM 的几率就被大大降低了,因为元空间使用的是本地内存,这样元空间的大小就只和本地内存的大小有关了,从而大大降低了 OOM 的问题。

2.2 降低运维成本

因为元空间使用的是本地内存,这样就无需运维人员再去专门设置和调整元空间的大小了。

3.方法区发展史

在 HotSpot 虚拟机中,方法区的实现经历了以下 3 个阶段:

  1. JDK 1.6 及之前:方法区使用永久代实现,静态变量存放在永久代
  2. JDK 1.7 :“去永久代”的前置版本,还存在永久代,不过已经将字符串常量池和静态变量从永久代移到了堆上
  3. JDK 1.8 及以后:无永久代,使用元空间(存放在本地内存中)实现方法区,常量保存在元空间,但字符串常量池和静态变量依然保存在堆中

总结

永久代和元空间都是 HotSpot 虚拟机对《Java 虚拟机规范》中方法区的实现,在 JDK 1.8 之前 HotSpot 是使用永久代来实现方法区的,但这样会导致 JVM 调优比较困难,且容易发生 OOM 的问题,而 JDK 1.8 及之后,使用的是元空间存放在本地内存中的方式来替代永久代的,这样就降低了 OOM 发生的可能性,也是 JRockit 和 HotSpot 融合之后的改动之一。

参考 & 鸣谢

openjdk.org/jeps/122

本文已收录到 Gitee 开源仓库《Java 面试指南》,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。Java 面试有它就够了:超全 Java 常见面试题,持续更新…

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13227.html

(0)

相关推荐

  • 常见的金融数据_redis几种数据类型的使用场景

    常见的金融数据_redis几种数据类型的使用场景高日耀 资深数据库内核研发 毕业于华中科技大学,喜欢研究主流数据库架构和源码,并长期从事分布式数据库内核研发。曾参与分布式 MPP 数据库 CirroData 内核开发(东方国信),现主要负责 MyS

    2023-04-24
    150
  • 优化循环流程:Python中的continue和break使用技巧

    优化循环流程:Python中的continue和break使用技巧在Python的循环结构中,continue和break是两个非常常用的关键字。continue用于跳出本次循环,进入下一次循环;而break用于直接跳出整个循环,继续执行其余的代码。这两个关键字都可以优化循环流程,提高代码效率。

    2024-01-10
    102
  • 使用time.sleep(1)进行Python编程休眠操作

    使用time.sleep(1)进行Python编程休眠操作在进行Python编程过程中,我们常常需要进行休眠操作,即程序暂停一段时间。这时,我们可以使用Python中的time模块中的sleep()函数来实现。休眠操作在处理网络请求、爬虫、文件读写等领域都有广泛应用。

    2024-05-30
    65
  • GRIT协议——分布式事务方案

    GRIT协议——分布式事务方案本文介绍了GRIT协议的基本思想,该思想在IEEE国际数据工程国际会议(ICDE)2019上宣布,并提供了使用该协议的一部分为JanusGraph实现事务性存储后端的示例。该示例着重于只有一个数据库…

    2023-03-06
    155
  • sqlserver是什么_仅怎么读

    sqlserver是什么_仅怎么读SQL Server中STATISTICS IO物理读和逻辑读的误区 大家知道,SQL Server中可以利用下面命令查看某个语句读写IO的情况 SET STATISTICS IO ON 那么这个命令

    2023-02-15
    140
  • mysql 常用语句_数据库常用语句

    mysql 常用语句_数据库常用语句把工作常用的mysql命令整理一下,省的用的时候在到处找 1.常用命令 1.1登录 mysql -u root -p 2.常用语句 2.1 生成随机数 若在 i<=R<=j 范围内生成随机数 FLO...

    2023-04-09
    140
  • 容器化|在 S3 备份恢复 RadonDB MySQL 集群数据[通俗易懂]

    容器化|在 S3 备份恢复 RadonDB MySQL 集群数据[通俗易懂]作者:程润科、钱芬 视频:钱芬 上一篇文章我们演示了如何快速实现 MySQL 高可用集群部署,以及部署集群的校验和卸载方式。本文将演示如何对集群进行备份和恢复。 部署版本为 RadonDB MySQL

    2023-05-13
    141
  • web项目踩坑过程[通俗易懂]

    web项目踩坑过程[通俗易懂]sql函数设计: 一开始本来是直接用Java的jdbc直接传输操作语句的。但后来学了存储过程发现存储过程可以提高不少的效率。就重构了自己对数据库的操作代码。包括:开启,查找,修改,关闭。 开启:直接使

    2022-12-22
    149

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注