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 中,程序计数器.虚拟机栈.本 ...
随机推荐
- OI界的梗
%%% 在C++"%"是取模的意思,简称模,是膜拜大佬的意思(%越多,语气越强) 蒟蒻 他本是一种可以吃的植物(就是魔芋),可是因为他谐音"巨弱",所以,他被用 ...
- Revit二次开发环境配置
# 文章概述 你是否刚接触 Revit 二次开发,面对复杂的开发环境无从下手? 你是否想快速实现一个带交互对话框的插件,却不知从何调用 TaskDialog? 你是否部署插件时频频失败,搞不清 .ad ...
- 问界M9同款“黑科技”上车,智界S7堪称“全能战士”
坊间一直流传着这样一句话:没有人能空着手从华为门店里走出来. 这是对华为的产品和服务坚持以客户为中心.致力满足千人千面需求的最高评价.对于这一观点,作为经常逛华为门店的科技自媒体,懂懂笔记也是高度认同 ...
- 高速数据通信卡设计原理图:基于DSP TMS320C6678+FPGA XC7V690T的6U VPX信号处理卡
基于DSP TMS320C6678+FPGA XC7V690T的6U VPX信号处理卡 概述 本板卡基于标准6U VPX 架构,为通用高性能信号处理平台,系我公司自主研发.板卡采用一片TI DSP T ...
- 【Cesium】九、Cesium点击地图获取点击位置的坐标,并在地图上添加图标
文章目录 一.前言 二.实现方法 三.App.vue 一.前言 查找发现好几种方法可以获取到点击位置的坐标.这里我实现需求就不深究学习了.将几位大佬的方法学习过来稍微整合了一下. 本文参考文章: ce ...
- 传统算法之Canny亚像素边缘检测及将离散边缘点链接成线条的优化和探讨。
边缘检测方面传统的算法中最为经典的就是Canny算法,但是标准的Canny是不具有亚像素精度的,而且得到的结果是一堆离散的边缘点,提取亚像素的方式有很多种,这个在网络上还有一些资料,而如何将离散点链接 ...
- [ARC081E] Don't Be a Subsequence 题目分析
题目概述 求所有不是 A 的子序列的最短小写英文字母字符串中字典序最小的一个. 分析 一个类似于 CSP2025-S 中第三题的动态规划. 倒着做. 设 \(f_i\) 表示以 \(A_i\) 为开头 ...
- VC入门宝典三(String)
CString 何志丹 主要内容: 1,主要函数的实现 2,常用函数 3.CString与char []的相互转换 4,将NULL字节放入CString中 vc中最主要函数不易理解. CString: ...
- P10912 [蓝桥杯 2024 国 B] 数星星
P10912 [蓝桥杯 2024 国 B] 数星星 题意简介 给定一棵 \(n\) 个节点的树和 \(L,R\),询问有多少个子图 \(G\),满足该子图是一棵树,树中存在一个节点 \(u\),其度数 ...
- 软件神器 --- 安卓离线AI OCR 之OCR助手、文字识别
免费神经网络引擎离线OCR文字识别