java gc 模型_java JVM GC与内存模型

一、垃圾收集算法

1.1 标记-清除算法

算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它是最基础的收集算法,会带来两个明显的问题:效率问题和空间问题(标记清除后会产生大量不连续的碎片)

7a4c47a18c8cc6b4b2d079612c895683.png

1.2 标记-复制算法

为了解决效率问题,“复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。

1a0ae3fe532ad231b157cd74bfcad36b.png

1.3 标记-整理算法

根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一段移动,然后直接清理掉端边界以外的内存。

41b84342465da9edc031a9a07a6786bc.png

1.4 分代回收

Java 垃圾回收机制最基本的做法是分代回收。内存中的区域被划分成不同的世代,对象根据其存活的时间被保存在对应世代的区域中。一般的实现是划分成3个世代:年轻、年老和永久。内存的分配是发生在年轻世代中的。当一个对象存活时间足够长的时候,它就会被复制到年老世代中。对于不同的世代可以使用不同的垃圾回收算法。

二、垃圾收集器

垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法、火车算法)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚拟机中的垃圾收集器。HotSpot虚拟机中是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。

Java有四种类型的垃圾回收器:

串行垃圾回收器(Serial Garbage Collector)

并行垃圾回收器(Parallel Garbage Collector)

并发标记扫描垃圾回收器(CMS Garbage Collector)

G1垃圾回收器(G1 Garbage Collector)

JDK7/8后,HotSpot虚拟机所有收集器及组合

95746ac57d68d4cb2acac2cd02728908.png

8efa2a203c80ef4867bb300d990fdd56.png

三、如何判断一个对象是否应该被回收

常用的方法有以下两种,由于引用计数法存在互相引用导致无法进行GC的问题,所以目前JVM虚拟机多使用对象可达性分析算法.

1.引用计数法;

2:对象可达性分析.

可达性分析法

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

5c756be94b655837e2e417643745f5a2.png

四、Java四种引用

JDK 1.2以前,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。

c59e3bf971dbc42520d8c89546f3002a.png

⑴强引用(StrongReference)

强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。  ps:强引用其实也就是我们平时A a = new A()这个意思。

⑵软引用(SoftReference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

⑶弱引用(WeakReference)

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

⑷虚引用(PhantomReference)

“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

五、运行时数据区

cc3b1f0f5e04c0d740beba55820971d5.png

1. 程序计数器

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完。

另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

2. Java虚拟机栈

与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是Java方法执行的内存模型。

Java内存可以粗糙的区分为堆内存(Heap)和栈内存(Stack),其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。

局部变量表主要存放了编译器可知的各种数据类型、对象引用。

3. 本地方法栈

和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行Java方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。

4. 堆

Java虚拟机所管理的内存中最大的一块,Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage Collected Heap).从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代:在细致一点有:Eden空间、From Survivor、To Survivor空间等。进一步划分的目的是更好地回收内存,或者更快地分配内存。

5. 方法区

方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。

HotSpot虚拟机中方法区也常被称为 “永久代”,本质上两者并不等价。仅仅是因为HotSpot虚拟机设计团队用永久代来实现方法区而已,这样HotSpot虚拟机的垃圾收集器就可以像管理Java堆一样管理这部分内存了。但是这并不是一个好主意,因为这样更容易遇到内存溢出问题。 相对而言,垃圾收集行为在这个区域是比较出现的,但并非数据进入方法区后就“永久存在”了。

6. 运行时常量池

运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译期生成的各种字面量和符号引用)

7. 直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致OutOfMemoryError异常出现。

JDK1.4中新加入的NIO(New Input/Output)类,引入了一种基于通道(Channel) 与缓存区(Buffer) 的I/O方式,它可以直接使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了在Java堆和Native堆之间来回复制数据。

本机直接内存的分配不会收到Java堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。

Java中堆和栈的区别

堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。

栈中一般存放的是局部变量(方法中的变量或某代码段里(比如for循环))

六、 内存分配与回收策略

1. 对象优先在Eden区分配

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

Minor Gc和Full GC 有什么不同呢?

新生代GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。

老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。

2. 大对象直接进入老年代

大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。

3. 长期存活的对象将进入老年代

既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别那些对象应放在新生代,那些对象应放在老年代中。虚拟机给每个对象一个对象年龄(Age)计数器。

4. 动态对象年龄判定

为了更好的适应不同程序的内存情况,虚拟机不是永远要求对象年龄必须达到了某个值才能进入老年代,如果Survivor 空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需达到要求的年龄。

七、其他常见问题

调用System.gc()会通知GC开始工作,但是GC真正开始的时间不确定.

finalize()方法什么时候被调用?析构函数(finalization)的目的是什么?

一旦垃圾回收器准备释放对象占用的内存,将首先调用该对象的finalize()方法,并且下一次垃圾回收动作发生时,才真正回收对象占用的内存空间。finalize是Object类的一个方法。

如果对象的引用被置为null,垃圾收集器是否会立即释放对象占用的内存?

不会,在下一个垃圾回收周期中,这个对象将是可被回收的。

类加载的五个过程:加载、验证、准备、解析、初始化。

几种常用的内存调试工具:jmap、jstack、jconsole。

Java中的内存溢出(OutOfMemoryError)是如何造成的?

(1)PerGern Space 程序中使用了大量jar或class,使Java虚拟机装载类空间不够。

解决:调参XX:PermSize 和 XX:MaxPermSize 、减少jar包,减少类的重复加载

(2)Java Heap Space Java虚拟机创建了太多的对象。

解决:调参Xms(初始堆大小)Xmx(最大堆大小)、检查死循环或不必要创建的重复对象

(3)unable to create new native Thread JVM占用了太多内存空间,而在JVM中创建线程还要再操作系统中也创建线程。

解决:调整JVM中线程大小。

JVM参数

配置描述

-Xms

初始化堆内存大小

-Xmx

堆内存最大值

-Xmn

新生代大小

-XX:PermSize

初始化永久代大小

-XX:MaxPermSize

永久代最大容量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jvm内存模型和垃圾回收(GC)是Java程序中重要的概念。 Java虚拟机(JVM内存模型定义了Java程序中对象的分配和回收。它包括了堆、栈、方法区和程序计数器。Java内存模型(JMM)则用于规定多线程环境下的内存访问和操作顺序。 GC是垃圾收集器自动完成的过程,用于回收不再使用的对象,释放内存空间。JVM会根据系统环境和内存需求来决定何时进行GC。我们也可以通过调用System.gc()方法手动触发一次垃圾回收,但是具体的回收时机由JVM决定。需要注意的是,手动调用System.gc()方法并不推荐,因为它会消耗较多的资源。 垃圾收集器是实现垃圾回收的具体实现。它们采用不同的算法和策略来收集和回收垃圾对象。Java中有多种垃圾收集器可供选择,如Serial、Parallel、CMS(Concurrent Mark Sweep)和G1(Garbage-First)等。每个垃圾收集器都有不同的特点和适用场景,可以根据应用程序的需求进行选择和配置。 因此,JVM内存模型定义了对象的分配和回收方式,而垃圾回收器则是具体实现了垃圾回收的过程,根据不同的算法和策略来回收不再使用的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JVM内存模型与垃圾回收](https://blog.csdn.net/weixin_40980639/article/details/125934179)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值