JVM 堆内存模型

news2024/11/15 4:22:26

方法区和永久代的关系

方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来

《Java 虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。 方法区和永久代的关系很像 Java 中接口和类的关系,类实现了接口,而永久代就是 HotSpot 虚拟机对虚拟机规范中方法区的一种实现方式。 也就是说,永久代是 HotSpot 的概念,方法区是 Java 虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现,其他的虚拟机实现并没有永久代这一说法

方法区实在虚拟机规范里面被定义的,不同的虚拟机对这个定义的实现不同,方法区是jvm规范中定义的永久代是虚拟机厂商HotSpot 对方法区的具体的实现,在别的jvm实现的厂商中就有可能不是叫永久代。在HotSpot 虚拟机中在 jdk1.7 版本之前的方法区实现叫永久代(PermGen space),jdk1.8 之后叫做元空间(Metaspace)。

主要存放class和元数据的信息,class被加载的时候就会被放入永久代,gc不会在主程序运行期间对永久代进行清理,这样会导致一个问题,就是永久代区域会随着加载的class的增多而胀满,最终抛出OOM异常

新生代和老年代

jvm中的堆分为新生代和老年代。

  • 新生代用来存放新生的对象,新生代中的对象朝生夕死,所以会频繁的触发 minor (脉了)GC 进行垃圾回收。新生代分为 eden 区、survivor from 区和 survivor to 区。eden区是java新对象的出生地,如果新创建的对象占用内存很大的话就会直接分配到老年代。当eden区的内存不足时就会触发 minor gc 对新生代进行一次垃圾回收。survivor from 区存放的是上一次minor gc 的幸存者,它将作为这一次gc的被扫描者。survivor to 区会保留这一次gc的幸存者。
  • 新生代 minor gc 的流程是:它采用的复制算法,首先eden区和survivor from区中存活的对象复制到survivor to区域,并将它们的年龄加一。然后清空eden区和survivor from区中的对象,接着将survivor from和survivor to互换,也就是原先的survivor to成为下一次gc时的survivor from。(这样要注意的是,如果有对象的年龄达到了老年代的标准,就放进老年代;如果survivor to区域的空间不够的话,就会通过分配担保机制,将多出来的对象提前转到老年代,但老年代要进行担保的前提是自己本身还有容纳这些对象的剩余空间,由于无法提前知道会有多少对象存活下来,所以这里是取之前每次晋升到老年代的对象的平均大小作为经验值,与老年代的剩余空间做比较)
  • 老年代主要存放生命周期较长的内存对象,所以不会频繁的进行垃圾回收。老年代采用的是标记清除算法,也就是首先扫描一次老年代,标记出存活对象,然后回收没有标记的对象。

java8之前,jvm堆中还有一块称作永久代的区域,主要存放class和元数据的信息,class被加载的时候就会被放入永久代,gc不会在主程序运行期间对永久代进行清理,这样会导致一个问题,就是永久代区域会随着加载的class的增多而胀满,最终抛出OOM异常

java8移除了永久代,取而代之的是一个叫做元数据区的概念,也叫做元空间。元空间和永久代是类似的,但它们最大的区别是元空间并不在虚拟机中,而是使用的本地内存,因此默认情况下,元空间的大小仅受本地内存的限制。也就是类的元数据放入本地内存中,字符串池和类的静态变量放入java堆中,这样可以加载多少类的元数据就由系统实际可用空间来控制了

为什么移除永久代

大致意思就是说,为了 JRockit 和 Hotspot 融合工作,JRockit客户不需要配置永久代,因为JRockit没有永久代

除了为了融合适配移除永久代以外还有其他原因:

  • 永久代设置空间大小是很难确定的,因为可能某个实际的业务场景中有不断的类加载等工作,但是元空间时使用本地内存,默认情况下时手本地大小限制的。

  • 调优困难,一般来说这个区域的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻。但是这部分区域的回收有时又确实是必要的。以前sun公司的Bug列表中,曾出现过的若干个严重的Bug就是由于低版本的HotSpot虚拟机对此区域未完全回收而导致内存泄漏。方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不在使用的类型。

JVM 内存模型

在这里插入图片描述
堆和方法区逻辑上是分开的,但是在物理内存上两者又是连续的
再精确一些的话,实际上是

在这里插入图片描述
java7之前方法区和老年代是相连的,所以永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。

在Java8中,元空间(Metaspace)登上舞台,方法区存在于元空间(Metaspace)。同时,元空间不再与堆连续,而且是存在于本地内存(Native memory,也称作直接内存),当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC ,元空间不会触发fullGC

在这里插入图片描述

元空间保存在本地内存中的好处是什么呢?

  • 原因一:因为直接内存,JVM将会在IO操作上具有更高的性能,因为它直接作用于本地系统的IO操作。而非直接内存,也就是堆内存中的数据,如果要作IO操作,会先复制到直接内存,再利用本地IO处理。
    从数据流的角度,非直接内存是下面这样的作用链:本地IO --> 直接内存 --> 非直接内存 --> 直接内存 --> 本地IO

而直接内存是:本地IO --> 直接内存 --> 本地IO

  • 原因二:整个永久代有一个 JVM 本身设置固定大小上线,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,并且永远不会得到java.lang.OutOfMemoryError。

设置元空间大小

可以使用 -XX:MaxMetaspaceSize 标志设置最大元空间大小,默认值为 unlimited,这意味着它只受系统内存的限制
-XX:MetaspaceSize 调整标志定义元空间的初始大小如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。

JVM 常用配置参数(Java 8)

日志

-XX:+PrintFlagsFinal,打印JVM所有参数的值
-XX:+PrintGC,打印GC信息
-XX:+PrintGCDetails,打印GC详细信息
-XX:+PrintGCTimeStamps,打印GC的时间戳
-Xloggc:filename,设置GC log文件的位置
-XX:+PrintHeapAtGC查看 GC 前后的堆、方法区可用容量变化
-XX:+PrintTenuringDistribution,查看熬过收集后剩余对象的年龄分布信息
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime 查看 GC 过程中用户线程并发时间以及停顿的时间

参考文档
https://www.javanav.com/val/acbb4071b64240b49145a1baf7856551.html

dump 设置

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof,当 OOM 发生时自动 dump 堆内存信息到指定目录

内存设置

-Xms,设置堆的初始化内存大小
-Xmx,设置堆的最大内存
-Xmn,设置新生代内存大小
-Xss,设置线程栈大小
-XX:NewRatio,新生代与老年代比值
-XX:SurvivorRatio,新生代中Eden区与两个Survivor区的比值,默认为8,即Eden:Survivor:Survivor=8:1:1
-XX:MaxTenuringThreshold,从年轻代到老年代,最大晋升年龄。CMS 下默认为 6,G1 下默认为 15
-XX:MetaspaceSize,设置元空间的大小,第一次超过将触发 GC
-XX:MaxMetaspaceSize,元空间最大值
-XX:MaxDirectMemorySize,用于设置直接内存的最大值,限制通过 DirectByteBuffer 申请的内存
-XX:ReservedCodeCacheSize,用于设置 JIT 编译后的代码存放区大小,如果观察到这个值有限制,可以适当调大,一般够用即可

设置垃圾收集相关

-XX:+UseSerialGC,设置串行收集器
-XX:+UseParallelGC,设置并行收集器
-XX:+UseConcMarkSweepGC,使用CMS收集器
-XX:ParallelGCThreads,设置Parallel GC的线程数
-XX:MaxGCPauseMillis,GC最大暂停时间 ms
-XX:+UseG1GC,使用G1垃圾收集器

CMS 垃圾回收器相关

-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction,与前者配合使用,指定MajorGC的发生时机
-XX:+ExplicitGCInvokesConcurrent,代码调用 System.gc() 开始并行 FullGC,建议加上这个参数
-XX:+CMSScavengeBeforeRemark,表示开启或关闭在 CMS 重新标记阶段之前的清除(YGC)尝试,它可以降低 remark 时间,建议加上
-XX:+ParallelRefProcEnabled,可以用来并行处理 Reference,以加快处理速度,缩短耗时

G1 垃圾回收器相关

-XX:MaxGCPauseMillis,用于设置目标停顿时间,G1 会尽力达成
-XX:G1HeapRegionSize,用于设置小堆区大小,建议保持默认
-XX:InitiatingHeapOccupancyPercent,表示当整个堆内存使用达到一定比例(默认是 45%),并发标记阶段就会被启动
-XX:ConcGCThreads,表示并发垃圾收集器使用的线程数量,默认值随 JVM 运行的平台不同而变动,不建议修改

在这里插入图片描述

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

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

相关文章

如何整理自己的前端面试题库

compose 题目描述:实现一个 compose 函数 // 用法如下: function fn1(x) {return x 1; } function fn2(x) {return x 2; } function fn3(x) {return x 3; } function fn4(x) {return x 4; } const a compose(fn1, fn2, fn3, fn4); console.log(a(1)); // 1432111实现代码…

基于Java+SpringBoot+Vue前后端分离书店购书系统设计与实现

博主介绍:✌全网粉丝3W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌ 博主作品:《微服务实战》专栏是本人的实战经验总结,《Spring家族及…

Tomcat部署及多实例

Tomcat部署及多实例一、Tomcat简介1、Tomcat核心组件2、什么是JSP二、Tomcat数据流向1、Tomcat数据流向2、Tomcat-Nginx数据流向三、Tomcat服务部署安装1、安装jdk包2、解压Tomcat所需的安装包3、在/etc/profile添加环境变量4、启动服务并查看5、在浏览器网页验证6、创建用户&a…

flink常用算子介绍

flink任务中【Transformation 数据转换】是对数据进行操作,有 Map、FlatMap、Filter、KeyBy 、Reduce 、Fold 、Aggregations、Window 、WindowAll 、Union 、Window join 、Split 、Select 、Project 等,通过对数据的操作,转换成想要的数据&…

【设计模式】4.建造者模式

概述 将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况。由于实现了构建和装配的解耦。不…

【沐风老师】3DMAX一键玻璃门生成器使用教程

3DMAX一键玻璃门生成器使用方法详解 3dMax一键玻璃门生成器是在3dMax中自动创建三维玻璃门模型的高效脚本。有6种风格的玻璃门,它可以在Archviz项目中灵活应用,同时为3D艺术家节省大量时间。 【适用版本】 3dMax 2018.2及更高版本 【安装方法】…

day37|完全背包、518. 零钱兑换 II、377. 组合总和 Ⅳ 复健运动

完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。 完全背包和01背包问题唯一不同…

什么是MES系统?本文解释得很清楚了

MES(英文Manufacturing Execution System的缩写),即生产执行系统,是近几年发展起来的企业信息化系统,目前在发达国家已经普遍推广。 MES软件是介于ERP(企业资源计划系统)和自控系统&#xff08…

百度前端训练营

视频:前端训练营开营仪式20220627_哔哩哔哩_bilibili http://bit.baidu.com/productsBuy?id248 一、Git安装与使用【因为重装系统,所以重新装一次环境】 查看电脑32位还是64,安装git TortoiseGit 及TortoiseGit 汉化包 下载64位对应的版本…

Java集合概述(Collection集合)

目录集合一、集合与数组二、集合类体系结构三、泛型(约定集合存储数据类型)四、Collection集合常用API五、Collection集合的遍历方式5.1 迭代器遍历5.2 增强for循环(for each):5.3 lambda表达式六、Collection集合存储自定义类型的对象七、常见数据结构集合 一、集合与数组 数…

【设计模式】9.桥接模式

概述 现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系: 我们可以发现有很多的类,假如我们再增加一个形状或再增加一种颜色,就需要创建更多的类。 试…

redis 05 篇——主从复制

redis 05 篇——主从复制1. 前言1.1 什么是复制?1.1.1 复制概述1.1.2 主从复制的架构1.2 为什么要使用主从复制?1.3 主从复制主要的命令配置2. 准备工作3. 核心配置3.1 主服务器3.2 从服务器4. 实例演示4.1 简单实例——两台服务器4.1.1 同一服务多个red…

小程序:使用分包异步化解决一个分包引入另一个分包的组件/函数的问题

背景 我们一般使用小程序插件的时候,喜欢将其放在分包中,因为插件体积会打包进主包内,很容易造成主包体积超过 2M 从而无法发布,我们暂且叫这个有插件的分包叫分包P,这时候另外两个业务分包XY,想引入这个分…

从Java培训班出来好找工作吗?

个人觉得这个问题要从两方面来看,首先是培训班的Java课程质量如何,是否贴合用人单位实际需求,学出来的技术能对口;其次是培训班是否保障就业,有就业机会渠道推荐,比如老学员内推、合作企业人才输送以及企业…

【Spring Cloud Alibaba】008-Sentinel

【Spring Cloud Alibaba】008-Sentinel 文章目录【Spring Cloud Alibaba】008-Sentinel一、服务雪崩1、概述2、解决方案常见的容错机制二、Sentinel:分布式系统的流量防卫兵1、**Sentinel** 概述简介特性Sentinel 的开源生态Sentinel 的历史2、Sentinel 基本概念资源…

低代码系统能够解决哪些痛点?

低代码系统能够解决哪些痛点?如果用4句话去归纳,低代码开发可以解决以下问题—— 为企业提供更高的灵活性,用户可以突破代码的限制自主开发业务应用;通过减少对专业软件开发人员的依赖,公司可以快速响应市场上的新业务…

cartographer中分支定界法理解——为什么能保证上界

定界原理 储存的不同分辨率栅格图,为保证上边界正确性,即高层中的评分一定高于其底层节点的评分,压缩的地图并非直接从原图固定间隔采样,而是将固定间隔中所有坐标概率值最大值作为低分辨率地图。 理解: 1、其在计算…

ESP32中MQTT通讯

MQTT文档介绍 一、在PC上可以使用 MQTT X 工具:(参考地址) 1、客户端下载:MQTT X 工具下载地址 2、EMQX服务器下载地址 3.打开命令行工具,进入目录运行EMQX服务。 电脑左下角,右键开始->运行->输…

“双碳”目标下二氧化碳地质封存技术应用前景及模型构建

我国二氧化碳地质封存技术起步较晚,目前仍没有一套相对完整的行业规范;且就该技术而言,涉及环节众多,理论相对复杂,对于行业的新入局者不太友好。因此,结合时代背景,我们首次尝试对二氧化碳地质…

升级多语言,应用国际化_三叠云

国际化配置 路径 表单设计 >> 字段属性 功能简介 【字段】新增 「国际化配置」 这是一个和国际化配合的功能,可以在用户通过切换不同的语言环境时,表单的标题、提示语等将会根据相应的语言环境切换到相应的表单字段标题、提示语,使…