JVM基础学习(二):内存分配策略与垃圾收集技术
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进行扫描。
垃圾收集算法
垃圾收集算法这里介绍三种:
- 标记-清除算法
- 标记-复制算法
- 标记-整理算法
标记-清除算法
标记-清除算法是最早出现也是最基础的算法,其执行步骤为:
- 标记出需要回收的对象(标记);
- 统一回收掉所有已被标记的对象(清除);
- 或者第一步标记出存活的对象,第二步清理没有被标记的对象;
标记-清除算法的缺点如下:
- 执行效率不稳定,与需要被标记的对象数量相关;
- 内存碎片化问题,标记、清除之后会产生大量不连续的内存碎片,可能会导致后续如果需要分配较大对象时无法找到足够的连续对象从而触发另外一次GC;
标记-复制算法
标记-复制算法简称复制算法,解决的是标记-清除算法中面对大量可回收对象执行效率低的问题。
最早的标记-复制算法是一种称为“半区复制”的算法,其将可用内存按照容量大小划分为大小相等的两块,一块用以平时使用,另外一块用以GC时复制还存活的对象。
标记-复制算法是现在的商用Java虚拟机常用的算法,但是“半区复制”算法所浪费的内存过多达到了整个内存区域的一半,所以后续又进行了很多的改进;
Appel式回收
“Appel式回收”是一种更优化的半区复制分代策略,其将内存区域分为一块较大的Eden空间与两块较小的Survivor空间,每次分配内存的时候只使用一块Eden空间与一块Survivor空间;
“Appel式回收”的具体做法是:
存放对象的时候只会使用Eden空间与一块Survivor空间,然后垃圾收集的时候会将存活的对象移到另外一块未被使用的Survivor区域。
其实就相当于是将存活对象一直有一个区域可以存放,这样便避免了内存空间的浪费。
HotSpot虚拟机的Serial、Parnew等新生代收集器均采取了这种策略设计新生代的内存布局。
标记-整理算法
标记-整理算法是针对老年代对象的存亡特征所提出的有针对性的算法。标记步骤并没有进行改变,整理步骤时,是将所有存活的对象都向内存对象一端移动,然后直接清理掉边界以外的内存。
若移动存活对象,那么便在对象移动过程中必须全程暂停用户应用程序才能进行,被称为“Stop The World”。
若不移动对象,那么内存碎片化问题只能依赖更为复杂的内存分配器与内存访问器解决。
总结
以上便是内存分配策略与垃圾收集技术的理论基础,下一篇博客介绍现代JVM的实现细节。
JVM基础学习(二):内存分配策略与垃圾收集技术的更多相关文章
- JVM系列四(内存分配策略).
一.概要 前面的文章介绍了对象的创建过程,其中第三步 -- 分配内存,只是简单的介绍了分配的方式 -- 指针碰撞.空闲列表,其实内存在堆上分配还大有文章嘞. 对象的内存分配,往大方向上讲,就是在堆上分 ...
- [jvm]垃圾回收与内存分配策略
一.垃圾回收算法 概述 JVM中,当创建的对象不再被使用的时候,此时我们认为他是无用的“垃圾”:在现代主流的商用jvm中,都是通过可达性分析来判断对象是否存活的.这个算法的基本思想是通过一系列“GCR ...
- jvm垃圾回收器与内存分配策略
一.判断对象存活的算法 1.引用计数算法 (1)概念:给对象中添加一个引用计数器每当有一个地方引用它时,计数器值加1:当引用失效时,计数器就减1:任何时刻计数器为0的对象就是不可能再被使用的. (2) ...
- JVM·垃圾收集器与内存分配策略之垃圾收集器!
1.Serial(串行)收集器(新生代都采用复制算法) 这是个单线程的收集器:即 当他工作的时候,会停掉虚拟机所有的线程!(Stop The World)
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
- jvm系列 (二) ---垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 前言:本文基于<深入java虚拟机>再加上个人的理解以及其他相关资料,对内容进行整理浓缩总结.本文中的图来自网络,感谢图的作者.如果有不正确的地方,欢迎指出. 目 ...
- JVM学习总结四——内存分配策略
之前几篇我们介绍了jvm的内存模型以及垃圾回收机制,而本篇我们将介绍几个JVM中对象在分配内存是应该遵循的策略.毕竟,想要去优化程序,不仅要考虑垃圾回收的过程,还要从对象内存分配的角度减少gc的代价. ...
- JVM学习--内存分配策略(持续更新)
一.前言 最近学习<深入java虚拟机>,目前看到内存分配策略这块.本文将进行一些实践. 二.内存分配策略 1.大对象直接进入老年代 书中提到了: 下面进行测试,代码如下: public ...
- JVM学习笔记-第三章-垃圾收集器与内存分配策略
JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...
随机推荐
- Kubernetes最佳实践之腾讯云TKE 集群组建
作者陈鹏,腾讯工程师,负责腾讯云 TKE 的售中.售后的技术支持,根据客户需求输出合理技术方案与最佳实践,为客户业务保驾护航.使用 TKE 来组建 Kubernetes 集群时,会面对各种配置选项,本 ...
- day 8 求平均数
fun()函数的功能:计算形参x所指数组中N个数的平均值,(这里全部取浮点数) 并输出,在将大于平均值的数放在形参y所指的数组中,在主函数输出. 效果还不错: 还存在需要优化的分析:其实存到y数组中的 ...
- leetcode 787. K 站中转内最便宜的航班
问题描述 有 n 个城市通过 m 个航班连接.每个航班都从城市 u 开始,以价格 w 抵达 v. 现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到从 src 到 dst ...
- 【C++】字符串处理
字符串处理 标签:c++ 目录 字符串处理 一.输入 1. scanf()函数 2. gets()函数 3. getchar()函数 二.输出 1. printf()函数 2. puts()函数: 3 ...
- 【刷题-LeetCode】230. Kth Smallest Element in a BST
Kth Smallest Element in a BST Given a binary search tree, write a function kthSmallest to find the k ...
- 解决new Thread().Start导致高并发CPU 100%的问题
背景 之前接手一个项目的时候,发现到处是 new Thread(()=>{ //do something }).Start(); 这么做的目的,无非是为了减少页面等待时间提高用户体验,把一些浪费 ...
- IoC容器-Bean管理XML方式(引入外部属性文件)
IoC操作Bean管理(引入外部属性文件) 1,直接配置数据库信息 (1)配置德鲁伊连接池 (2)引入德鲁伊连接池依赖jar包 2,通过引入外部属性文件配置数据库连接池 (1)创建外部属性文件,pro ...
- Linux 学习2
1.配置好阿里云yum源生成yum缓存下载nginx,并且启动nginx服务,使用浏览器访问,nginx页面 yum源的工作目录是? https://www.cnblogs.com/dlh-lmsh/ ...
- c#开方,平方,sin函数计算
平方运算 private double m; private double n=Math.Pow(m,2.0); 开平方运算 System.Math.Sqrt(数字); double保留两位小数 Ma ...
- Java流程控制03:顺序结构
顺序结构 Java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行. 顺序结构是最简单的算法结构.从上到下 语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处 ...