前言:Java与C++之间有一堵高墙,主要是有内存动态分配和垃圾收集技术组成的。墙外的人想要进来,墙内的人想要出去。

一、概述

  每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的。内存的分配和回收都具有确定性。

二、对象已死?

  垃圾收集器在对堆进行回收之前,不能确定哪些“对象”活着,哪些“对象”死去。

  1、引用计数算法

    在对象中,添加一个引用计数器,当有一个地方引用它时,计数器的值加一;引用失效的时候,计数器的值减一;任何时刻,计数器为零的对象不能被再次使用。这样就存在一个问题,如果两个对象之间相互引用,是否永远不能够被回收。代码如下所示:

package com.example.dayevery;
public class ReferenceCountingGC{
public Object instance = null;
private static final int _1MB = 1024*1024;
// 测试 是否被回收
private byte[] bigSize = new byte[2 * _1MB];
public static void TestGc (){
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
// 测试 objA和objB是否被系统回收
System.gc();
}
public static void main(String[] args) {
// 提交执行
TestGc();
System.out.println("1");
}
}

  通过结果发现,虚拟机最终并没有因为两个对象之间互相引用就放弃回收它们,也就是说Java虚拟机并不是通过引用技术算法来判断对象是否存活。

  2、可达性分析算法

    当前主流算法(Java.C#)的内存管理子系统,采用可达性分析算法来判断对象是否存活。

    算法思路:通过一系列称之为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径称之为“引用链”,如果某一个对象和GC Roots集合之间没有任何的引用链相连,则证明此对象之间不能被再次使用。

    GC Roots:除了固定的集合之外,根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可能会有其他的“对象”临时的加入,从而构成了完整的GC Roots集合。

三、生存还是死亡?

  当在可达性分析算法中,被标记为“死亡”的时候,该对象并不是真正的“死亡”,除了这一次的标记之外,还有第二次自救,那就是采用finalize()方法,从而让自己跟某一个起始节点集合挂上联系。

  finalize()方法:能且只能执行一次,如果失败,那么就会被回收。这是一个被可以在Java语言中被遗忘的方法。

四、回收方法区

  方法区回收的垃圾主要有两部分:废弃的常量和不再使用的类型。其中废弃的常量,举个例子,一个字符串“java”进入常量池中,没有任何的地方引用这个字符串,这属于废弃的常量。

  不再使用的类型要满足以下几点。1、该类的所有实例被回收。2、该类的类加载器已经被全部回收。3、该类对应的java.lang.Class类对象没有在任何地方引用。

五、垃圾收集算法

  垃圾收集算法可以划分为“引用计数式垃圾收集”和“追踪式垃圾收集”。本文主要介绍追踪式垃圾收集。

  首先要介绍分代收集理论,它建立在两个分代假说之上:1、弱分代假说。2、强分代假说。此后,还延伸出来“跨代引用假说”:存在相互引用的两个对象应该倾向于同时生存或者同时消亡的。

  针对不同的区域安排与里面存储对象存亡特征相匹配的垃圾收集算法:1、标记 - 复制算法。2、标记 - 消除算法。3、标记 - 整理算法。

  1、标记 - 消除算法

    标记 - 消除算法是最基础的算法,主要分为“标记”和“清除”两部分,标记过程就是对象是否属于垃圾的判定过程。

    算法流程:首先标记出所有需要回收的对象,标记完成之后,统一回收掉所有被标记的对象。同时也存在两个缺点:1、执行效率不太稳定。2、内存空间的碎片化问题。

  2、标记 - 复制算法

    为了解决标记 - 清除算法,面对可回收对象时执行效率低的问题,提出采用“半区复制”,将内存划分为大小相等的两块,每次只是使用其中的一块。当其中一块内存用完之后,就将还存活的对象复制到另一块的上面,然后把已经使用过的内存空间一次性的清理到。最明显的缺点:可用内存缩小为原来的一半。

    标记 - 复制算法中的“半区复制”在89年发生了变化,针对“新生代”朝生夕灭的特点,采用了一种更加优化的半区复制分代策略,称为Appel式回收:将新生代的内存分为一块较大(80%)的Eden空间和两块较小(10%)的Survivor空间。

    每次使用Eden空间和一块Survivor空间,在垃圾回收的时候,将仍然存活的对象直接复制未被使用的Survivor空间中,当所需空间不能满足存活对象要求,采用“逃生门”的安全设计,依赖其他内存区域(老年代)进行分配担保。PS:有点像是银行借贷这种。

  3、标记 - 整理算法

    算法过程:标记 - 整理算法和标记 - 清除算法的第一步是相同的,但是标记 - 整理算法不能够直接对可回收对象进行清理,而是让所有的存活对象都往内存空间的一端移动,直接清理掉边界以外的内存。

六、HotSpot虚拟机的算法细节实现

    见下一篇博客。

Java虚拟机(JVM):第三幕:自动内存管理 - 垃圾收集器与内存分配策略的更多相关文章

  1. 深入理解java虚拟机_第三章(上)----->垃圾收集器与内存分配策略

    1.  前言 这一版块内容比较多,分为两篇文章来做笔记.本文讲述上半部分垃圾收集部分;下一篇文章写内存分配部分. 概述 对象已死吗? 引用技术算法 可达性分析算法 再谈引用 两次标记 回收方法区 2. ...

  2. Java虚拟机的内存管理----垃圾收集器

    1.Serial收集器 优点,是简单而高效,单线程避免了线程交互的开销. 缺点,进行垃圾回收时需要Stop the world(暂停所有用户线程). 2.ParNew收集器 它是Serial收集器的多 ...

  3. JVM内存管理---垃圾收集器

    说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态 ...

  4. 《深入java虚拟机》读书笔记之垃圾收集器与内存分配策略

    前言 该读书笔记用于记录在学习<深入理解Java虚拟机--JVM高级特性与最佳实践>一书中的一些重要知识点,对其中的部分内容进行归纳,或者是对其中不明白的地方做一些注释.主要是方便之后进行 ...

  5. 《深入理解java虚拟机》第三章 垃圾收集器与内存分配策略

    第三章 垃圾收集器与内存分配策略 3.1 概述 哪些内存需要回收 何时回收 如何回收 程序计数器.虚拟机栈.本地方法栈3个区域随线程而生灭. java堆和方法区的内存需要回收.   3.2 对象已死吗 ...

  6. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  7. 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略

    垃圾收集器与内存分配策略 详解 3.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第三章 ,为了整理思路,简单记录一下,方便后期查阅. 3.2 对象已死吗 在垃圾收集器进行回收 ...

  8. java虚拟机 jvm 出入java栈 栈空间内存分配

    java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关.线程最基本的执行行为就是函数的调用.每次函数调用其实是通过java栈传递数据的. 数据结构中 ...

  9. 如何设置Java虚拟机JVM启动内存参数

    Tomcat默认的Java虚拟机JVM启动内存参数大约只有64MB或者128MB,非常小,远远没有利用现在服务器的强大内存,所以要设置Java虚拟机JVM启动内存参数.具体设置方法为: Tomcat修 ...

  10. 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.3.垃圾收集器与内存分配策略

    1.学习目的 当需要排查各种内存溢出. 内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节. Java内存运行时区域的各个部分,其中程序计数 ...

随机推荐

  1. Transformer算法的应用

    目录 1. 引言 2. 技术原理及概念 2.1. 基本概念解释 2.2. 技术原理介绍 2.3. 相关技术比较 3. 实现步骤与流程 3.1. 准备工作:环境配置与依赖安装 3.2. 核心模块实现 4 ...

  2. C# - XMLHelper :一个操作XML的简单类库

    下午写了一个操作XML文件的类库,后来不用了,水篇文章存个档 整体功能 XMLHelper.cs主要提供以下功能: 加载XML文件:从文件路径或字符串中加载XML文档,并返回XmlDocument对象 ...

  3. 从0开发WebGPU渲染引擎:开篇

    大家好,本系列会从0开始,开发一个基于WebGPU的路径追踪渲染器,使用深度学习降噪.DLSS等AI技术实现实时渲染:并且基于自研的低代码开发平台,让用户可以通过可视化拖拽的方式快速搭建自定义的Web ...

  4. Visual Studio Code调试和发布ASP.NET Core Web应用

    前言 上一篇文章主要讲了Visual Studio Code安装C#开发工具包并编写ASP.NET Core Web应用有兴趣的同学可以去看看,今天咱们主要是要讲讲如何在VS Code中调试和发布AS ...

  5. Typecho左右侧广告区域展示恋爱线时间

    该教程适用typecho动态博客框架,handsome主题,展示恋爱线时间,效果立于博客网页左侧右侧等区域,展示如下: 教程 typecho动态博客框架,handsome主题下,将下面代码粘贴到后台设 ...

  6. 数据库连接池之c3p0-0.9.1.2,线上偶发APPARENT DEADLOCK,如何解?

    前言 本篇其实是承接前面两篇的,都是讲定位线上的c3p0数据库连接池,发生连接泄露的问题. 第二篇讲到,可以配置两个参数,来找出是哪里的代码借了连接后没有归还.但是,在我这边的情况是,对于没有归还的连 ...

  7. linux内核vmlinux的编译过程之 --- $(kallsyms.o)详解(九)

    在编译完依赖 vmlinux.o 后,链接 vmlinux 之前,构建系统还要编译依赖目标 $(kallsyms.o).接下来就对 kallsyms 进行一个简单的解释. 一. 引言 1.符号的概念 ...

  8. 手机免root安装最新青龙面板(非Alpine term | Zero term软件)

    使用软件:Termux 可以用于任何支持qemu虚拟机的环境.APP 制作了基本的系统环境.开发环境和青龙面板环境.多个虚拟机,按需求下载 官方网站:https://api.wer.plus 群:10 ...

  9. 王道oj/problem17

    网址:http:oj.lgwenda.com/problem17 思路:指针其实就是存储地址的一个空间,LinkList=LNode* 代码: #define _CRT_SECURE_NO_WARNI ...

  10. VS Code 有哪些好用的插件呢?【持续更新】

    一.画图工具:vscode-drawio   功能:在 VSCode 中画流程图.数据流图等等.        使用方法:     创建一个后缀名为 .drawio 的文件,然后用 VSCode 打开 ...