JVM(三)

举报
一颗小谷粒 发表于 2025/07/31 18:45:07 2025/07/31
【摘要】 垃圾回收Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配,堆区是垃圾收集器管理的主要区域。开发者使用 System.gc() 方法可以提醒 JVM 进行垃圾回收,但不能强制。分区回收现在收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分为:新生代和老年代。进一步划分的目的是更好地回收内存,或者更快地分配内存。新生代 GC (Minor GC) :新生代垃圾回收非常...

垃圾回收

Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配,堆区是垃圾收集器管理的主要区域。

开发者使用 System.gc() 方法可以提醒 JVM 进行垃圾回收,但不能强制。

分区回收

现在收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分为:新生代和老年代。进一步划分的目的是更好地回收内存,或者更快地分配内存。

  • 新生代 GC (Minor GC) :新生代垃圾回收非常频繁,回收速度也比较快。
  • 老年代 GC (Major GC) :老年代垃圾回收次数较少,回收速度也明显更慢。

初次分配对象

新生代分为 eden 区和 survive 区, 其中 eden 区占用内存空间更大。

大多数情况下,对象在新生代 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC。

长期存活对象

虚拟机给每个对象设置一个年龄计数器。如果对象经过一次 Minor GC 后仍然能够存活,将从 eden 移动到 survive 空间中。对象每熬过一次 Minor GC,年龄就增加 1 岁。当它的年龄增加到一定程度(默认为 15 岁),就会晋升到老年代。

survive 区分为 from 区和 to 区两块大小相等的内存空间。Minor GC 执行时,会将 eden 区和 from 区中的存活对象复制到 to 区,清除 eden 区和 from 区内存。再把这些存活对象从 to 区移动回 from 区。

当老年代也没有足够空间进行分配时,虚拟机将发起一次 Major GC。

大对象

需要大量连续内存空间的对象(如字符串、数组)直接进入老年代,可以避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。

指令概念

指令是指示计算机执行某种操作的命令,如:数据传送指令、算术运算指令、位运算指令、程序流程控制指令、串操作指令、处理器控制指令。指令不同于我们所写的代码,一行代码按照操作的逻辑可以分成多条指令。

举个例子:int a = 1; 这段代码大致可以分为两条指令:1.加载常量1;2.将常量1赋值给变量a。

指令重排序

只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑顺序不一致,这个过程就叫做指令的重排序。

指令重排序的意义:使指令更加符合 CPU 的执行特性,最大限度的发挥机器的性能,提高程序的执行效率。

指令重排序分类

指令重排序主要分为三种,在这里主要讨论 JVM 中的指令重排序。

  1. 编译器重排序:JVM 中完成
  2. 指令级并行重排序
  3. 处理器重排序:CPU 中完成

指令重排序原则

如果程序中操作A在操作B之前,那么线程中操作A将在操作B之前执行。(只对指令内部重排序,不在指令间重排序)

  • As-If-Serial语义

不管怎么进行指令重排序,单线程内程序的执行结果不能被改变。

编译器和处理器对存在依赖关系的操作都不会对其进行重排序。只有不存在依赖关系的操作有可能进行重排序。

Happens-Before原则

保证正确同步的多线程程序的执行结果不被改变。

对于被同步的操作,如果操作 A 先于操作 B,那么 A 操作的执行结果将对 B 操作可见,而且 A 操作的执行顺序排在 B 操作之前。

管理锁定规则:一个unlock操作happen—before后面(时间上的先后顺序)对同一个锁的lock操作。 (如果线程1解锁了monitor a,接着线程2锁定了a,那么,线程1解锁a之前的写操作都对线程2可见(线程1和线程2可以是同一个线程))

防止指令重排

volatile关键字通过“内存屏障”来防止指令被重排序。

为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

Java内存模型采取保守策略(见缝就插)

在每个volatile写操作的前面插入一个StoreStore屏障。 在每个volatile写操作的后面插入一个StoreLoad屏障。 在每个volatile读操作的后面插入一个LoadLoad屏障。 在每个volatile读操作的后面插入一个LoadStore屏障。

Synchronized 把多线程执行环境改变为单线程执行环境,无需关心指令重排序(单线程执行结果不会改变)。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。