Java基础17——常见内存分配策略、垃圾回收相关

119 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

常见内存分配策略

大多数情况下对象在新生代 Eden 区分配,当 Eden 没有足够空间时将发起一次Minor GC大对象直接进入**老年代分配。经历过第一次 Minor GC** 后Eden区中仍然存活且能被 Survivor 区容纳的对象就会被移动到 Survivor区中并将年龄设置为1,并且每经历一次 Minor GC 年龄就加1 ,当增加到一定程度(默认15)就会晋升到老年代。若Survivor区内存不够,则部分Eden区对象直接晋升老年代

如果在Survivor区相同年龄的所有对象大小的总和大于 Survivor 的一半,年龄不小于该年龄的对象就可以直接进入老年代

空间分配担保

目的:避免FullGC过于频繁。

MinorGC前虚拟机必须检查老年代的最大可用连续空间是否大于新生代对象总空间,如果满足则说明这次 Minor GC 安全。如果不满足,JVM会查看HandlePromotionFailure 参数是否允许担保失败,如果允许会继续检查老年代最大可用连续空间是否大于历次晋升老年代对象的平均大小,如果满足就执行Minor GC,否则执行FullGC。

简述JVM的对象分配内存策略

指针碰撞法: 使用指针作为分界指示器使用中未使用的内存位于指针两边,通过指针挪动完成分配。

空闲列表法: 对于堆内存不规整的情况,虚拟机维护一个列表记录可用内存,在分配时从列表中找一块足够大的空间分配给对象更新列表记录

java对象内存分配如何保证线程安全

(1)采用CAS机制失败重试的方式保证更新操作的原子性,但效率低,一般不使用该方法。

(2)每个线程在堆中预分配内存,给对象分配内存时直接在预分配的内存中分配,预分配的内存称为做TLAB,常用该策略,

为什么有TLAB ( Thread Local Allocation Buffer ) ?

●堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据

●由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区中划分内存空间是线程不安全

●为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。

从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM为每个线程分配了一个私有缓存区域,它包含在Eden空间内。

多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称之为快速分配策略。

据我所知所有OpenJDK衍生出来的JVM都提供了TLAB的设计。

垃圾回收相关

垃圾判断算法

  • 引用计数法:设置引用计数器,对象被引用时计数器加 1,引用失效时计数器减 1,如果计数器为 0 则被标记为垃圾。缺点:会存在对象间循环引用的问题。空间开销:计数器。时间开销:对计数+-
  • 可达性分析法:将GC Roots的根对象作为起始节点,依次寻找对应的引用节点没有被搜到的对象则视为垃圾GC Roots 的根对象包括虚拟机栈本地方法栈引用的对象类静态变量引用的对象、常量引用的对象。

垃圾回收算法

  • 标记复制算法将可用内存划分为大小相等的两块空间,每次只使用其中一块空间,当使用的空间满了,就将存活的对象复制到另一块空间,再清理掉当前使用的空间缺点是总有一半的空间无法使用。
  • 标记清除算法:先标记需清除的对象之后统一回收缺点效率不高,会产生大量不连续的碎片
  • 标记整理算法:先标记存活的对象,然后让存活对象复制一端,再回收端边界外的对象。

简述分代收集算法

根据对象的存活周期将内存划分为几块,分别采用适当的收集算法

一般将堆分为新生代老年代。:

新生代,使用标记复制算法。 eden->survivor1 survivor2->survivor1

老年代,混合使用标记清除算法标记整理算法

Finalize()方法

Java语言提供了对象终止( finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。

垃圾回收此对象之前,总会先调用这个对象的finalize()方法

finalize()方法允许在子类中被重写,用于在对象被回收时进行资源释放。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件套接字数据库连接等。

image-20220322161532764

对象的三种状态:

image-20220322161807426

简述java的引用类型

  • 强引用:关联对象不会被回收,采用 new 方法创建。
  • 软引用:关联对象只有内存不够的情况下会被回收,采用 SoftReference类创建。
  • 弱引用:关联对象被垃圾收集器碰到就回收,只能存活到下一次垃圾回收发生之前,采用WeakReference类来创建。
  • 虚引用:关联对象可跟踪垃圾回收过程,被回收时会收到系统通知不能通过虚引用获取对象,且必须与引用队列联合使用。