深入理解Java虚拟机之经典垃圾收集器

深入理解Java虚拟机之经典垃圾收集器

为什么需要垃圾收集器

Java虚拟机需要对内存中无用的对象进行清理,以便为新对象腾出空间,避免OutOfMemoryError异常。Java虚拟机中的垃圾收集器可以自动回收无用对象,减少程序员手动管理的工作量。

垃圾回收的基本过程

垃圾回收的基本过程分为两个步骤:标记和垃圾回收。

标记阶段:
- 遍历根对象,将根对象活跃的对象标记为存活。
- 遍历存活对象的所有引用,将其所包含的对象标记为存活。
- 重复上一步的过程,直到所有可到达的对象都标记为存活,这个过程被称为“可达性分析”。

垃圾回收阶段:
- 将重复利用的内存空间挑选出来,这部分内存空间将作为下一轮存储使用过的对象空间。
- 遍历整个堆空间,将未被标记的对象移回到空间池,将处理过的对象移动到下一轮可用的内存空间中。

常见的垃圾回收算法

标记-清除算法

标记-清除算法分为两个阶段:标记,清除。
- 标记阶段:所有的存活对象都被标记,未被标记的都是垃圾对象。
- 清除阶段:被判定为垃圾的对象将会被清除。

缺陷:
1. 标记阶段和清除阶段都需要暂停整个应用程序,会影响用户体验。
2. 清除后内存空间不连续而且散乱,会影响后续分配内存的效率。
3. 对象引用可以被多个对象引用,如果其中一个对象被回收,则其可能影响其他对象的使用,引发dangling pointer问题。

复制算法

复制算法将可用的内存空间与垃圾回收保持完全分离,垃圾对象被回收后,剩下的内存会被整理,从而避免内存碎片化的问题。

步骤:
1. 将总可用内存空间一分为二,每个内含一半的空间。
2. 选取一半的空间进行对象分配。
3. 遍历已分配的对象,将其复制到另一半空间中。
4. 清理已分配的半部分空间,使其可变为下一轮分配使用。

复制算法的不足:
1. 只有一半的内存作为可用空间,不满足如今内存容量需求。
2. 复制算法只有一半的内存作为可用空间,正常情况下每一个对象被复制的次数都比较少,如果要存放所有的对象,那么我们需要将这个内存空间分成N份,复制N-1次才能将对象复制到这N份内存当中,复制的次数会明显增多。

标记-整理算法

去除标记-清除算法的缺陷,可以用标记-整理算法。标记-整理算法在标记阶段让不活跃的对象变成垃圾,清除阶段将所有存活的对象压缩到连续的内存空间中,并把未压缩的内存清理干净。

步骤:
1. 标记存活对象。
2. 将存活对象移到连续的内存地址中,而不是清除所有未被标记的存活对象。
3. 重置所有指针,以正确指向移动后的位置。
4. 清理不需要的内存区域。

示例说明

示例1:标记-清除算法的不足

在代码中定义了一个对象o1,并将其引用赋值给了o2

Object o1 = new Object();
Object o2 = o1;

在执行过程中,o1o2两个引用在栈内存上均指向堆内存中的同一对象。

若在外部执行了如下操作:

o1 = null;

此时,堆内存中的对象被标记为不再被引用,即为垃圾对象,但由于o2仍持有该对象的引用,此对象并不会被标记-清除算法回收,这就导致了内存泄漏。

示例2:复制算法的缺陷

在以下一个数组中进行对象分配:

Object[] arr = new Object[1000000];

当使用复制算法将数组分割为两个可用的内存空间进行对象分配时,如果数组的大小比分割后的空间还要大,就无法进行对象分配。此时需要使用滚动式压缩算法,在回收时将存活对象从内存里面移动到一端,并在移动后更新所有的被指向该对象的指针,从而减少内存压力。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入理解Java虚拟机之经典垃圾收集器 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java编码辅助工具Lombok用法详解

    Java编码辅助工具Lombok用法详解 Lombok是一个Java编码辅助工具,可以简化Java代码的编写。下面将详细讲解Lombok的用法。 安装 Lombok可以在Maven中央仓库中获取。在Maven项目中引入Lombok的依赖即可: <dependency> <groupId>org.projectlombok</gr…

    Java 2023年5月20日
    00
  • jsp中定义和使用方法示例介绍

    下面详细讲解“JSP中定义和使用方法示例介绍”的攻略。 一、定义和使用方法 1.1 定义方法 在JSP中定义方法,可以使用<%! %>标签。例如: <%! public int add(int num1, int num2) { return num1 + num2; } %> 以上代码定义了一个名为“add”的方法,该方法返回两个整…

    Java 2023年6月15日
    00
  • Java定时器Timer使用方法详解

    Java定时器Timer使用方法详解 在Java中,有时需要在程序中计划执行某些任务,或者需要按照一定的时间间隔来执行任务。在这种情况下,我们可以使用Java的定时器——Timer。 Timer概述 Java中的定时器类是java.util.Timer,它允许您在某个时间后执行某个任务,或者在某个时间间隔后重复执行某个任务。它是线程安全的,因此您可以同时计划…

    Java 2023年5月20日
    00
  • Spring Data JPA实现持久化存储数据到数据库的示例代码

    以下是详细的攻略: 一、什么是Spring Data JPA Spring Data JPA是Spring框架中对JPA(Java Persistence API)规范的封装。JPA是一种ORM(Object Relational Mapping)框架,用于将Java对象映射到关系型数据库。 Spring Data JPA对JPA的封装简化了数据访问层的开发…

    Java 2023年5月20日
    00
  • jvm垃圾回收算法详细解析

    垃圾回收算法的分类 垃圾回收算法可以分为两种:标记-清除算法(Mark-Sweep)和复制算法(Copying),还有它们的变体和组合。 标记-清除算法(Mark-Sweep):这是垃圾回收算法中最基础的一种算法。它将内存分成两部分,一部分被程序使用,另一部分则被垃圾回收机制使用。垃圾回收机制会遍历程序使用的内存空间,标记出未被使用的内存,然后将其清除。它的…

    Java 2023年5月19日
    00
  • Sprint Boot @ConditionalOnClass使用方法详解

    @ConditionalOnClass是Spring Boot中的一个注解,它用于根据类路径中是否存在指定的类来决定是否启用或禁用某个组件。在使用Spring Boot开应用程序时,@ConditionalOnClass是非常有用的。本文将详细介绍@ConditionalOnClass的作用和使用方法,并提供两个示例说明。 @ConditionalOnCla…

    Java 2023年5月5日
    00
  • 关于Java 获取时间戳的方法

    关于Java获取时间戳的方法有很多种,这里主要介绍两种比较常用的方法。 方法一:使用System类的currentTimeMillis()方法 long timestamp = System.currentTimeMillis(); System类是Java的一个内置类,其中的currentTimeMillis()方法返回的是当前时间距离1970年1月1日0…

    Java 2023年5月20日
    00
  • java单元测试JUnit框架原理与用法实例教程

    首先我们需要了解JUnit框架的原理和用法。JUnit是Java语言中最流行的单元测试框架之一,使用JUnit框架可以对Java应用程序进行单元测试。 一、JUnit框架原理 JUnit框架的原理主要是基于Java反射机制实现的。JUnit框架通过反射机制来查找待测试类中的测试方法,并按照一定的顺序执行测试方法,然后针对每一个测试方法进行断言,判断测试结果是…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部