Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来

垃圾收集概述

Java内存模型中的堆和方法区是垃圾收集技术所需要关注的终点,因为其他的区域会跟随线程的结束而自动回收。

而需要解决垃圾收集的首要目标便是解决如何判断一个对象已经不需要了从而自动进行回收;判断对象是否可以进行回收的算法可以分为引用计数算法可达性分析算法

对于Redis有一些了解的同学应该知道Redis的对象内存回收算法便是使用的引用计数算法;而JVM都是使用的可达性分析算法,在此我们只讨论可达性分析算法。

可达性分析算法

可达性分析算法简而言之便是从一些称为“GC Roots”的根对象作为起始节点集,根据引用关系向下搜索,搜索过的路径称为引用链,若某个对象到任何GC Roots对象都没有引用链,那么此对象便为不可达。

在Java技术体系中,固定作为GC Roots对象的包括以下几种:

  • 虚拟机栈中引用的变量(虚栈);
  • 方法区中类静态属性引用的对象(静);
  • 方法区中常量引用的对象(常);
  • 本地方法栈中引用的变量(本栈);
  • JVM虚拟机内部的引用(内);
  • 所有被同步锁持有的对象(锁);
  • 其他反映虚拟机内部情况的对象;

垃圾收集算法

从如何判定对象消亡的角度出发,垃圾收集算法可以划分为“引用计数式垃圾收集(直接垃圾收集)”与“追踪式垃圾收集(间接垃圾收集)”。

分代收集理论

分带收集理论是基于以下分代假说之上:

  • 弱分代假说:绝大多数对象都是朝生夕灭的;
  • 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡;
  • 跨代引用假说:跨代引用相对于同代引用来说仅占极少数;

以上的假说共同奠定了垃圾收集器的一致的设计原则:收集器应该将Java堆划分为不同的区域,然后根据回收对象的年龄分配到不同的区域中存储。

所以现代JVM垃圾收集器一般将Java堆划分为“新生代”与“老年代”;

针对不同分代的GC算法有以下几种:

  • 部分收集(Partial GC):不是完整收集整个Java堆的垃圾收集;

    • 新生代收集(Minor GC/Young GC):目标只是新生代的垃圾收集;
    • 老年代收集(Major GC/Old GC):目标只是老年代的垃圾收集,暂时只有CMS收集器实现了单独的老年代收集;
    • 混合收集(Mixed GC):目标是收集整个新生代以及部分老年代的垃圾收集,暂时只有G1收集器有这种行为;
  • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集;

跨代引用假说主要是解决跨越“新生代”与“老年代”的对象之间引用的问题,根据该假说所衍生出的对于跨代引用的解决方法是:

在“新生代”上建立一个全局的数据结构(记忆集),该结构将老年代划分为若干小块,标识“老年代”中存在跨代引用的内存区域。此后发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会假如GC Roots进行扫描。

垃圾收集算法

垃圾收集算法这里介绍三种:

  • 标记-清除算法
  • 标记-复制算法
  • 标记-整理算法

标记-清除算法

标记-清除算法是最早出现也是最基础的算法,其执行步骤为:

  1. 标记出需要回收的对象(标记);
  2. 统一回收掉所有已被标记的对象(清除);
  3. 或者第一步标记出存活的对象,第二步清理没有被标记的对象;

标记-清除算法的缺点如下:

  1. 执行效率不稳定,与需要被标记的对象数量相关;
  2. 内存碎片化问题,标记、清除之后会产生大量不连续的内存碎片,可能会导致后续如果需要分配较大对象时无法找到足够的连续对象从而触发另外一次GC;

标记-复制算法

标记-复制算法简称复制算法,解决的是标记-清除算法中面对大量可回收对象执行效率低的问题。

最早的标记-复制算法是一种称为“半区复制”的算法,其将可用内存按照容量大小划分为大小相等的两块,一块用以平时使用,另外一块用以GC时复制还存活的对象。

标记-复制算法是现在的商用Java虚拟机常用的算法,但是“半区复制”算法所浪费的内存过多达到了整个内存区域的一半,所以后续又进行了很多的改进;

Appel式回收

“Appel式回收”是一种更优化的半区复制分代策略,其将内存区域分为一块较大的Eden空间与两块较小的Survivor空间,每次分配内存的时候只使用一块Eden空间与一块Survivor空间;

“Appel式回收”的具体做法是:

存放对象的时候只会使用Eden空间与一块Survivor空间,然后垃圾收集的时候会将存活的对象移到另外一块未被使用的Survivor区域。

其实就相当于是将存活对象一直有一个区域可以存放,这样便避免了内存空间的浪费。

HotSpot虚拟机的Serial、Parnew等新生代收集器均采取了这种策略设计新生代的内存布局。

标记-整理算法

标记-整理算法是针对老年代对象的存亡特征所提出的有针对性的算法。标记步骤并没有进行改变,整理步骤时,是将所有存活的对象都向内存对象一端移动,然后直接清理掉边界以外的内存。

若移动存活对象,那么便在对象移动过程中必须全程暂停用户应用程序才能进行,被称为“Stop The World”。

若不移动对象,那么内存碎片化问题只能依赖更为复杂的内存分配器与内存访问器解决。

总结

以上便是内存分配策略与垃圾收集技术的理论基础,下一篇博客介绍现代JVM的实现细节。

JVM基础学习(二):内存分配策略与垃圾收集技术的更多相关文章

  1. JVM系列四(内存分配策略).

    一.概要 前面的文章介绍了对象的创建过程,其中第三步 -- 分配内存,只是简单的介绍了分配的方式 -- 指针碰撞.空闲列表,其实内存在堆上分配还大有文章嘞. 对象的内存分配,往大方向上讲,就是在堆上分 ...

  2. [jvm]垃圾回收与内存分配策略

    一.垃圾回收算法 概述 JVM中,当创建的对象不再被使用的时候,此时我们认为他是无用的“垃圾”:在现代主流的商用jvm中,都是通过可达性分析来判断对象是否存活的.这个算法的基本思想是通过一系列“GCR ...

  3. jvm垃圾回收器与内存分配策略

    一.判断对象存活的算法 1.引用计数算法 (1)概念:给对象中添加一个引用计数器每当有一个地方引用它时,计数器值加1:当引用失效时,计数器就减1:任何时刻计数器为0的对象就是不可能再被使用的. (2) ...

  4. JVM·垃圾收集器与内存分配策略之垃圾收集器!

    1.Serial(串行)收集器(新生代都采用复制算法)     这是个单线程的收集器:即 当他工作的时候,会停掉虚拟机所有的线程!(Stop The World)

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

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

  6. jvm系列 (二) ---垃圾收集器与内存分配策略

    垃圾收集器与内存分配策略 前言:本文基于<深入java虚拟机>再加上个人的理解以及其他相关资料,对内容进行整理浓缩总结.本文中的图来自网络,感谢图的作者.如果有不正确的地方,欢迎指出. 目 ...

  7. JVM学习总结四——内存分配策略

    之前几篇我们介绍了jvm的内存模型以及垃圾回收机制,而本篇我们将介绍几个JVM中对象在分配内存是应该遵循的策略.毕竟,想要去优化程序,不仅要考虑垃圾回收的过程,还要从对象内存分配的角度减少gc的代价. ...

  8. JVM学习--内存分配策略(持续更新)

    一.前言 最近学习<深入java虚拟机>,目前看到内存分配策略这块.本文将进行一些实践. 二.内存分配策略 1.大对象直接进入老年代 书中提到了: 下面进行测试,代码如下: public ...

  9. JVM学习笔记-第三章-垃圾收集器与内存分配策略

    JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...

随机推荐

  1. 自定义Nginx日志格式获取IP地址的省市份信息

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6806672112477012493/ 在linux中nginx日志产生的格式是下面的配置: $remote_add ...

  2. Java CAS 原理详解

    1. 背景 在JDK 5之前Java语言是靠 synchronized 关键字保证同步的,这会导致有锁.锁机制存在以下问题: 在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问 ...

  3. C#进程调用FFmpeg操作音视频

    项目背景 因为公司需要对音视频做一些操作,比如说对系统用户的发音和背景视频进行合成,以及对多个音视频之间进行合成,还有就是在指定的源背景音频中按照对应的规则在视频的多少秒钟内插入一段客户发音等一些复杂 ...

  4. Spring Boot Admin,贼好使!

    Spring Boot Admin(SBA)是一个开源的社区项目,用于管理和监控 Spring Boot 应用程序.应用程序可以通过 http 的方式,或 Spring Cloud 服务发现机制注册到 ...

  5. Java不限制从键盘输入一个数组

    Java不限制从键盘输入一个数组 在写算法的时候,需要从键盘输入一个数组,一直不会,最近看了几篇博客学会了,下面用二分查找举例: package com.基础; import java.util.Sc ...

  6. Java安全之C3P0利用与分析

    Java安全之C3P0利用与分析 目录 Java安全之C3P0利用与分析 写在前面 C3P0 Gadget http base C3P0.getObject() 序列化 反序列化 Class.forN ...

  7. http协议和https协议的区别

    超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂 ...

  8. LoadRunner编写socket性能测试脚本

    利用LoadRunner编写socket性能测试脚本 一.概述 Loadrunner拥有极为丰富的工具箱,供予我们制造出各种奇妙魔法的能力.其中就有此次要讨论的socket套接字操作. 二.socke ...

  9. ApacheCN 深度学习译文集 2020.9

    协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 不要担心自己的形象,只关心如何实现目标.--<原则>,生活原则 2.3.c 在线阅读 ApacheCN 面试求职交流群 72418 ...

  10. [NOI Online #1 提高组]

    A 首先从 \(t = 2\) 的特殊部分分出发. 不难发现这个操作是很不直观的,于是可以考虑对于每个操作 \((u, v)\) 在 \(u, v\) 之间连一条无向边. 显然连通块之间要分开考虑,对 ...