java 垃圾收集器与内存分配策略
如何判断对象是否需要被回收?
引用计数法,
给对象增加一个引用计数器,当计数器为0即该对象没有被引用时,说明该对象可以被回收。但是主流Java虚拟机没有采用这种方法,主要原因是无法解决循环引用的问题。比如A引用B,B引用A,计数器均不为0,但是不能被访问到。
可达性分析法,
主流的商用程序语言(Java、C#、Lisp)使用可达性分析法(Reachability Analysis)。基本思想就是通过一系列的称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明该对象是不可达的,可以被回收。
GC Roots对象包括:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- 方法区中类静态属性引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI(即一般说的Native方法)引用的对象。
逃脱回收的最后机会
可达性分析中不可达的对象,需要检查是否要执行finalize()方法,如果对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,则标记为“没有必要执行”,会进入待回收队列。如果被判定有必要执行finalize()方法,这个对象会被放入叫做F-Queue的队列中,由虚拟机创建的低优先级Finalizer线程去触发finalize()方法,但是不保证会等待运行结束(防止一直运行导致阻塞)。如果finalize()方法中,对象重新与引用链上的任何对象简历关联,比如把自己(this)赋值给某个类变量或者对象的成员变量,那在第二次标记时将会被移出待回收集合。但是第二次进行可达性分析时,如果被标记,则直接进入待回收集合,因为任何对象的finalize()方法只会被系统自动调用一次。

回收方法区
方法区(或者HotSpot虚拟机中的永久代)也是会进行回收的,Java虚拟机规范中不要求虚拟机在方法区实现垃圾收集,而且方法区垃圾收集“性价比”比较低。永久代回收主要包括:废弃常量和无用的类。废弃常量比如说字符串,没有引用的时候就会被回收。
无用的类判断比较复杂,满足一下条件可以被回收,并且虚拟机参数可调:
- 该类的所有实例都已经被回收,也就是Java堆中不存在该类的任何实例。
- 加载该类的ClassLoader已经被回收。
- 该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
大量使用反射、动态代理、CGLib等ByteCode框架、动态生成JSP以及OSGI这类频繁自定义ClassLoader的场景都需要虚拟机具备类写在的功能,以保证永久代不会溢出。
垃圾收集算法
标记-清除法,
首先标记需要回收的对象,在标记完后统一回收被标记的对象。最基础的收集算法。
不足:1.标记和清除效率都不高,2.标记清除后会产生大量不连续碎片,导致需要分配大对象时内存不够,导致另一次GC。
复制算法,
将可用内存划分为相等的两块,每次只使用其中一块。当一块用完后,将存活的对象移到另一块内存,将之前使用的内存一次清空。
优点:简单高效
不足:内存使用率低,只能使用一半的内存。
现代商业虚拟机都在用这种算法来回收新生代,研究发现并不需要对半分,一般会分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和一块Survivor,HotSpot默认Eden:Survivor为8:1,只会有10%的空间会被浪费。


标记-整理算法,
标记过程与标记-清楚算法的标记过程相同,后续步骤是让所有存活的对象都向一端移动,然后直接清理端边界以外的内存。
分代收集算法,
当前商业虚拟机的垃圾收集都采用分代收集(Generational Collection)算法,根据对象存活周期的不同将内存划分为几块。一般把Java堆分为新生代和老年代,根据各个年代的特点采用适当的收集算法。新生代每次GC大批对象死亡,只有少量存活,使用复制算法。老年代中对象存活率高、没有额外空间,必须使用“标记-清理”或者“标记-整理”算法进行回收。
垃圾收集器

内存分配与回收策略
分配规则不是百分之百确定的,其细节取决于当前使用的垃圾收集器组合,以及虚拟机中与内存相关的参数配置。
- 对象优先在Eden分配,
当Eden区没有足够的空间时,虚拟机将发起一次Minor GC。
- 大对象直接进入老年代,
大对象指,需要大量连续内存空间的Java对象,典型的是很长的字符串以及数组。大对象对虚拟机是一个坏消息,经常出现大对象容易导致内存还有不少空间时就提前出发GC。
- 长期存活的对象将进入老年代,
虚拟机给每个对象定义了一个对象年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移到Survivor空间中,并且对象年龄设为1.每在Survivor中“熬过”一次Minor GC,年龄增加一岁,增加到一定
程度(默认15岁),就将晋升到老年代。
- 动态对象年龄判定
如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。
- 空间分配担保
Minor GC前会检查老年代最大可用连续空间是否大于新生代所有对象空间,如果成立则Minor GC可以确保安全。如果不成立,会检查配置是否允许失败。如果允许失败,会继续检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如
果大于,将尝试进行一Minor GC,如果小于,或者不允许冒险,则改为进行Full GC。
refs:
《深入理解Java虚拟机》
https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
https://docs.oracle.com/javase/9/gctuning/toc.htm
java 垃圾收集器与内存分配策略的更多相关文章
- Java垃圾收集器与内存分配策略
程序的计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭:栈中的栈侦随着方法的进入和退出而有条不紊地执行出栈和如栈操作. 判断对象是不是已经死亡的方法: 一.引用计数算法: 给对象添加一个引用 ...
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
- 深入理解java虚拟机_第三章(上)----->垃圾收集器与内存分配策略
1. 前言 这一版块内容比较多,分为两篇文章来做笔记.本文讲述上半部分垃圾收集部分;下一篇文章写内存分配部分. 概述 对象已死吗? 引用技术算法 可达性分析算法 再谈引用 两次标记 回收方法区 2. ...
- 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)
1. 前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保 2. 垃圾 ...
- 《深入java虚拟机》读书笔记之垃圾收集器与内存分配策略
前言 该读书笔记用于记录在学习<深入理解Java虚拟机--JVM高级特性与最佳实践>一书中的一些重要知识点,对其中的部分内容进行归纳,或者是对其中不明白的地方做一些注释.主要是方便之后进行 ...
- 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 详解 3.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第三章 ,为了整理思路,简单记录一下,方便后期查阅. 3.2 对象已死吗 在垃圾收集器进行回收 ...
- 《深入理解java虚拟机》第三章 垃圾收集器与内存分配策略
第三章 垃圾收集器与内存分配策略 3.1 概述 哪些内存需要回收 何时回收 如何回收 程序计数器.虚拟机栈.本地方法栈3个区域随线程而生灭. java堆和方法区的内存需要回收. 3.2 对象已死吗 ...
- Java虚拟机垃圾收集器与内存分配策略
Java虚拟机垃圾收集器与内存分配策略 概述 那些内存须要回收,什么时候回收.怎样回收是GC须要完毕的3件事情. 程序计数器.虚拟机栈与本地方法栈这三个区域都是线程私有的,内存的分配与回收都具有确定性 ...
- 深入了解Java虚拟机(2)垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 由于JVM中对象的频繁操作是在堆中,所以主要回收的是堆内存,方法区中的回收也有,但是比较谨慎 一.对象死亡判断方法 1.引用计数法 就是如果对象被引用一次,就给计数器+1,否 ...
- GC之一--GC 的算法分析、垃圾收集器、内存分配策略介绍
一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...
随机推荐
- Why框架的突破,无需数据训练
ECT-OS-JiuHuaShan/ORCID:0009-0006-8591-1892 ▮ 检测到核心特性阐释请求 ▮ 启动「无数据训练范式」论证协议 核心论断:从数据拟合到规律显化 ECT-OS-J ...
- ffmpeg本地视频文件直播推流+web播放器无插件直播
这个场景中,我们可以直接利用强大的ffmpeg将本地文件,以直播的方式输出 ffmpeg -re -stream_loop -1 -fflags +genpts -i F:\05CACHE\ss.mp ...
- Rouyan:使用WPF/C#构建的基于LLM的快捷翻译小工具
前言 都说技术服务于业务,对我个人而言可能谈不上有什么业务,但是确实有一些个人的需求.我很喜欢C#也很喜欢WPF,最近刚学了Stylet这个框架,就想着先试着用它搞一个解决自己阅读英文文献一些小需求的 ...
- 2021年前端面试题-vue篇
1.多个组件之间如何拆分各自的state,每块小的组件有自己的状态,它们之间还有一些公共的状态需要维护,如何思考这块 (1)公共的数据部分可以提升至和他们最近的父组件,由父组件派发 (2)公共数据可以 ...
- 从0开始的FreeRTOS(3)
"从0开始的FreeRTOS"系列教程第三讲 作者:satori 这次我们开始介绍FreeRTOS的任务管理机制. 在第一讲中,我们知道了操作系统是在一个在内存中自动对任务进行调度 ...
- QT C++ 解决调试运行时报 The inferior stopped 错误
(1)报错信息和报错时调用堆栈 SignaI Received - Qt Creator The inferior stopped because it received a signal from ...
- ZKEACMS:基于ASP.Net Core开发的开源免费内容管理系统
前言 哈喽,大家好!我是码农刚子,大家应该都已和床分手,去上班了吧.国庆假期在家没事,试用了一下ZKEACMS,一个可视化拖拽的内容管理系统,今天给大家介绍一下. 简介 ZKEACMS也叫纸壳CMS, ...
- PCIe加速卡设计资料:416-基于Kintex Ultrasacle的万兆网络光纤 PCIe加速卡
一.产品概述 本卡为企业级别板卡,可用于数据中心,安全领域数据采集处理.标准PCI Express全高板,适用于普通服务器.工作站. 二 接口介绍 硬件规格 结构尺寸 标准PCI Exp ...
- Oracle Recovery Tools快速恢复重建ctl遗漏数据文件故障---惜分飞
标题:Oracle Recovery Tools快速恢复重建ctl遗漏数据文件故障 作者:惜分飞版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任的权利.] 数据库被强制打开,由于重 ...
- 一款基于 .NET 开源免费、高效且用户友好文件搜索工具!
前言 无论是工作中的项目文档,还是学习中的研究资料,高效地管理和搜索这些文件成为了我们提升工作效率的关键.今天大姚给大家分享一款基于 .NET 开源免费(MIT license).高效且用户友好的文件 ...