深入理解JVM(3)——垃圾收集策略详解
Java虚拟机的内存模型分为五部分:程序计数器、Java虚拟机栈、本地方法栈、堆、方法区。
程序计数器、Java虚拟机栈、本地方法栈都是线程私有的,也就是每个线程都拥有这三个区域,而且这三个区域会随着线程的创建而开始,随着线程的结束而销毁,那么垃圾收集器在何时清理这三个区域的问题就解决了。
堆和方法区是所有线程共享的区域,并且是在JVM开启的时候创建一直运行到JVM停止,因此它没办法根据线程的创建而创建,根据线程的结束而结束。堆中存放JVM在运行期间的所有对象,虽然每个对象的内存大小在加载该对象所属类的时候就已经确定了,但是究竟创建多少个这样的对象只能在程序运行期间才能知道;方法区中存放的类信息、静态成员变量和常量,类的加载是在程序运行过程中,当需要创建这个类的对象时才会加载这个类,JVM究竟需要加载多少个类也需要在程序运行期间才能确定。
一、堆内存的回收
- 如何判断那些对象需要被回收
首先判断一个对象无效的依据是这个对象不再被任何的对象或者变量所引用。
判断的方法主要有两种:引用计数法和可达性分析法;
引用计数法就是每一个对象都会有一个引用计数器,当给对象被引用一次计数器就加1,当断开一个引用计数器就减1,所以当引用计数器的值为0 的时候就表示该对象没有被任何的对象或者变量引用。
可达性分析法:所有的和GC Roots直接或者间接关联的对象都是有效对象,没有关联的都是无效对象,这里的GC Roots指的是:Java虚拟机栈中所引用的对象、本地方法区中静态属性所引用的对象、方法区中常量所引用的对象、本地方法栈中所引用的对象。
注意:引用计数法虽然简单但是存在一个严重的问题就是无法解决循环引用的问题。因此普遍使用的是可发性分析法判断一个对象是否有效。
- 回收无效对象的过程是什么
a) 首先判断这个对象是否覆盖了finalize()方法:如果这个对象没有覆盖这个方法,直接释放对象内存,如果该对象覆盖了这个方法并且这个方法还没有被执行,那么就将finalize()方法放到F-Queue队列中,
b) 执行F-Queue队列中的finalize()方法:虚拟机以较低的优先级执行这些finalize()方法,也不会确保所有的finalize()方法都会被执行,如果finalize()方法出现耗时情况虚拟机会直接停止执行并释放内存。
c) 对象重生或者死亡:如果执行finalize()方法的时候,this对象被别的对象或者变量引用,那么该对象就重生了,否者就会被直接释放内存。
二、方法区的内存回收
- 方法区中主要清楚的对象:废弃的常量和废弃的类
- 如何判断废弃常量:判断废弃的常量和废弃的对象是一样的,只要这个常量不再被任何的对象或者变量所引用,那么该常量就是一个废弃常量。
- 如何判断废弃的类:
a) 判断废弃的类要求的条件比较复杂
b) 该类多创建的所有对象都已经被回收
c) 加载该类的ClassLoader类已经被回收
d) 给类的Class类没有被任何的对象或者变量所引用。
三、垃圾收集算法
|
算法名称 |
算法的介绍 |
优点 |
缺点 |
引用区域 |
|
标记-清除算法 |
利用前面的判断方法判断出需要清除哪些数据,并给他们做上标记,然后清除被标记的数据。 |
该算法标记和清除的过程效率都很低,清除后会有大量的碎片空间,导致无法存储大对象,降低空间利用率。 |
||
|
复制算法 |
将内存分成两份,只在其中一块上存储数据,当需要回收垃圾时,也是首先标记出废弃的数据,然后将有用的数据复制到另一部分内存,再把第一块内存全部清除。 |
这种算法避免了碎片空间 |
但是内存被缩小一半,因为每次都要将有用的数据全部复制一遍,效率不高 |
新生代中使用:为了防止内存碎片化:堆内存的新生代进一步划分为:Eden区+Survior1区+Survior2区 |
|
标记-整理算法 |
在回收垃圾之前首先将所有被废弃的对象做上标记,然后将所有未被标记的对象移动到另一边,最后清空另一边区域即可 |
这是一种老年代的垃圾收集算法 |
||
|
分代收集算法 |
将内存划分为新生代和老年代。新生代中存放“朝生夕死”的对象,老年代中存放寿命较长的对象,然后再不同的区域使用不同的垃圾收集算法 |
四、如何解决空间利用率的问题:
在新生代中,由于大量的对象都是“朝生夕死”,也就是一次垃圾收集后只有少量对象存活,因此我们可以将内存划分成三块:Eden、Survior1、Survior2,内存大小分别是8:1:1。分配内存时,只使用Eden和一块Survior1。当发现Eden+Survior1的内存即将满时,JVM会发起一次MinorGC,清除掉废弃的对象,并将所有存活下来的对象复制到另一块Survior2中。那么,接下来就使用Survior2+Eden进行内存分配。通过这种方式,只需要浪费10%的内存空间即可实现带有压缩功能的垃圾收集方法,避免了内存碎片的问题。
五、什么叫做分配担保:
当JVM准备为一个对象分配内存空间时,发现此时Eden+Survior中空闲的区域无法装下该对象,那么就会触发MinorGC,对该区域的废弃对象进行回收。但如果MinorGC过后只有少量对象被回收,仍然无法装下新对象,那么此时需要将Eden+Survior中的所有对象都转移到老年代中,然后再将新对象存入Eden区。这个过程就是“分配担保”。
六、老年代为什么不使用复制算法而要使用标记-整理算法:
老年代中存放的对象一般寿命都比较长,因此每次垃圾回收之后都会有大量的对象存活,因此如果选用复制算法的话,每次需要复制大量的对象,会导致效率极低,而且在新生代中使用“复制算法”,当Eden+Survior中都装不下某个对象时,可以使用老年代的内存进行“分配担保”,而如果在老年代使用该算法,那么在老年代中如果出现Eden+Survior装不下某个对象时,没有其他区域给他作分配担保。因此,老年代中一般使用“标记-整理”算法。
七、Java中引用的种类:根据声明周期的长短,将引用分为四类:强引用、软引用、弱引用、虚引用。这四类引用的声明周期依次递减。
深入理解JVM(3)——垃圾收集策略详解的更多相关文章
- 理解JVM之垃圾收集器详解
前言 垃圾收集器作为内存回收的具体表现,Java虚拟机规范并未对垃圾收集器的实现做规定,因而不同版本的虚拟机有很大区别,因而我们在这里主要讨论基于Sun HotSpot虚拟机1.6版本Update22 ...
- 深入理解JVM(三)——垃圾收集策略具体解释
Java虚拟机的内存模型分为五个部分.各自是:程序计数器.Java虚拟机栈.本地方法栈.堆.方法区. 这五个区域既然是存储空间,那么为了避免Java虚拟机在执行期间内存存满的情况,就必须得有一个垃圾收 ...
- 深入理解JVM内存分配策略
理解JVM内存分配策略 三大原则+担保机制 JVM分配内存机制有三大原则和担保机制 具体如下所示: 优先分配到eden区 大对象,直接进入到老年代 长期存活的对象分配到老年代 空间分配担保 对象优先在 ...
- JVM之内存结构详解
对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug.同时,JVM也是面试环节的中重灾区.今天开始,<JVM详解>系列开启,带大家深入了解JVM相 ...
- JVM性能调优详解
前面我们学习了整个JVM系列,最终目标的不仅仅是了解JVM的基础知识,也是为了进行JVM性能调优做准备.这篇文章带领大家学习JVM性能调优的知识. 性能调优 性能调优包含多个层次,比如:架构调优.代码 ...
- [转帖]JVM性能调优详解
JVM性能调优详解 https://www.cnblogs.com/secbro/p/11833651.html 应该是 jdk8 以前的方法 貌似permsize 已经放弃这一块了. 前面我们学习了 ...
- 七牛云存储Python SDK使用教程 - 上传策略详解
文 七牛云存储Python SDK使用教程 - 上传策略详解 七牛云存储 python-sdk 七牛云存储教程 jemygraw 2015年01月04日发布 推荐 1 推荐 收藏 2 收藏,2.7k ...
- guava-retrying 源码解析(等待策略详解)
一.等待策略相关类: 1.等待策略接口:WaitStrategy接口 该接口只有一个方法,就是返回尝试失败之后,下一次尝试之前的等待时间.long computeSleepTime(Attempt f ...
- [转帖]Nginx服务器的六种负载均衡策略详解
Nginx服务器的六种负载均衡策略详解 咔咔侃技术 2019-09-11 17:40:12 一.关于Nginx的负载均衡 在服务器集群中,Nginx起到一个代理服务器的角色(即反向代理),为了避免单独 ...
随机推荐
- 简单有效:解决 Excel 打开 UTF-8 编码 CSV 文件乱码的 BUG
https://blog.csdn.net/Sukie_csdn/article/details/78752969
- python之工作目录和文件引用
1.参考 如何获得Python脚本所在目录的位置 Python 相对导入与绝对导入 还没细看 2.不考虑exe打包 sys.path[0] #顶层运行脚本的绝对目录 os.path.split(os. ...
- 【译】异步JavaScript的演变史:从回调到Promises再到Async/Await
我最喜欢的网站之一是BerkshireHathaway.com--它简单,有效,并且自1997年推出以来一直正常运行.更值得注意的是,在过去的20年中,这个网站很有可能从未出现过错误.为什么?因为它都 ...
- scrapy 基础使用以及错误方案
原先用的是selenium(后面有时间再写),这是第一次使用scrapy这个爬虫框架,所以记录一下这个心路历程,制作简单的爬虫其实不难,你需要的一般数据都可以爬取到. 下面是我的目录,除了main.p ...
- phpMyAdmin 安装教程全攻略
管理MYSQL数据库的最好工具是PHPmyAdmin,现在最新版本是phpMyAdmin 2.9.0.2,这是一个国际上开源的软件,一直在更新版本,你可以从 http://www.phpmyadmin ...
- JavaMelody 项目性能监控和调优工具
转自 JavaMelody 可以实现对内存.CPU.线程.JDBC 连接数.HTTP 请求执行时间.SQL 执行时间(分析 Top SQL).方法执行时间(分析系统方法性能瓶颈)等等的监控. 配置方式 ...
- Python交互图表可视化Bokeh:5 柱状图| 堆叠图| 直方图
柱状图/堆叠图/直方图 ① 单系列柱状图② 多系列柱状图③ 堆叠图④ 直方图 1.单系列柱状图 import numpy as np import pandas as pd import matplo ...
- NN:神经网络实现识别手写的1~9的10个数字—Jason niu
import numpy as np from sklearn.datasets import load_digits from sklearn.metrics import confusion_ma ...
- Nightmare Ⅱ HDU - 3085 (双向bfs)
Last night, little erriyue had a horrible nightmare. He dreamed that he and his girl friend were tra ...
- HDU 4185 Oil Skimming 【最大匹配】
<题目链接> 题目大意: 给你一张图,图中有 '*' , '.' 两点,现在每次覆盖相邻的两个 '#' ,问最多能够覆盖几次. 解题分析: 无向图二分匹配的模板题,每个'#'点与周围四个方 ...