当前位置: 首页 > news >正文

JVM阶段(4)-回收策略

1.概述

回忆一下,运行时数据区哪些部分会产生OOM异常,如果无休止的创建对象,或者类信息,或者往运行时常量池塞数据,都可能导致OOM。为了避免这种情况,就需要去考虑底层的垃圾收集。

那么,哪些内存需要回收。

什么时候来回收。

如何回收。

这三个问题,其实就是垃圾回收器的本质。当然,先从哪些内存需要回收说起。

其实主要就是堆和方法区,其它的都是线程私有,线程挂,直接无。

2.回收策略

关于回收策略,其实大多说的都是堆这一块,哪些对象需要回收。这就用到了引用计数法,以及可达性分析算法。

2.1 引用计数法

引用计数法,首先声明,这个算法Java之中是不用的。可以想想,底层支撑的数据结构,双向链表,注定了两个对象肯定是持有各自的引用的,要用这种算法无法回收。

引用计数法,可以理解为每个对象都有一个引用数,reference counting,当这个数为0时,代表了任何对象都没有引用该对象,它没用了,所以回收。

反向证明下,java内部使用的不是引用计数法。

package com.bo.jvmstudy.thirdchapter;

/**
 * @Auther: zeroB
 * @Date: 2022/8/31 20:46
 * @Description: 证明GC不是引用计数法
 * -Xmx20m -Xms20m -XX:+PrintGCDetails
 */
public class ReferenceCountingTest {

    //内部类设置个1M空间,明显点
    static class Obj{
        private Integer[] arr = new Integer[1024*1024];

        public Obj obj;
    }


    public static void main(String[] args) {
        Obj obj1 = new Obj();
        Obj obj2 = new Obj();
        obj1.obj = obj2;
        obj2.obj = obj1;

        obj1 = null;
        obj2 = null;

        /*
      ,[GC (System.gc()) [PSYoungGen: 2170K->504K(6144K)] 10362K->8948K(19968K), 0.0009356 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 504K->0K(6144K)] [ParOldGen: 8444K->710K(13824K)] 8948K->710K(19968K), [Metaspace: 2958K->2958K(1056768K)], 0.0057077 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
         */
        //根据日志
        System.gc();
    }
}

看一下打印出的GC日志:

[GC (System.gc()) [PSYoungGen: 2918K->488K(6144K)] 11110K->9263K(19968K), 0.0009433 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 488K->0K(6144K)] [ParOldGen: 8775K->1008K(13824K)] 9263K->1008K(19968K), [Metaspace: 3356K->3356K(1056768K)], 0.0050389 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 6144K, used 56K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)
  eden space 5632K, 1% used [0x00000000ff980000,0x00000000ff98e2b8,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 13824K, used 1008K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)
  object space 13824K, 7% used [0x00000000fec00000,0x00000000fecfc110,0x00000000ff980000)
 Metaspace       used 3363K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 366K, capacity 388K, committed 512K, reserved 1048576K

看样子是执行了两次GC,分析一下各个的含义:

[PSYoungGen: 2918K->488K(6144K)] 11110K->9263K(19968K), 0.0009433 secs]

PSYoungGen,从young这个词就可以看出来,这个是新生代。

6144K,当年新生代可用空间为6144K。即一个survior+Eden的区域大小。

2918K->488K,代表了原先由新生代有2918K的内存占用,GC后剩下的488K。回收了2M,没毛病。

19968K,代表的是整体的堆内存空间,新生代默认是整体堆空间的1/3,这里大致看起来确实是。

11110K->9263K,代表了堆整体从11110K回收到了9263K。

后面的时间就是消耗时间了。

后面的这个FullGC应该是我程序结束后,整体的一个FullGc.整体也可以看出来:

PSYoungGen:新生代

ParOldGen:老年代

Metaspace:元空间

垃圾回收回收的也主要是这几个区域。不过我分配了20M内存,如果换算的话,应该是20480K,但实际使用的只有19968K空间。其它的500多K的空间呢?

因为初学,猜测是另一个不被使用的survior区域。但是,从大小来说,20480/3/10,我这面计算下682.6666666666667,比500要大了不少。而且元空间并不占堆内存。后期回来再看吧。

言归正传,从2918K->488K(6144K)看出来,我们的两个对象还是被回收了。这里证明了引用计数法在java中其实并没有使用。

2.2 可达性分析算法

可达性分析算法,则是从定义的一些根对象(GCRoot)开始,搜索这些根对象直接或者间接所持有的对象,来形成一个个引用链。不在这些引用链上的对象,则代表没有其它对象持有,可以被回收。

那么,可以用作GC ROOT节点有哪些?

在虚拟机栈中(局部变量表)所引用的对象。

在方法区中静态属性所引用的对象。

在方法区中常量所引用的对象。

在本地方法栈JNI中引用的对象。

java虚拟机内部的引用,比如基础数据据类型对应的Class对象,常驻异常对象,以及系统类加载器。

被同步锁所持有的对象。

反应Java虚拟机内部情况的JMXBean,JVMTI注册的回调,本地代码缓存等。(这个没有懂)。

其实在测试OOM导出的hprof文件,也可以看到GCROOT这一系列对象,当然,暂时没有深究,后期学完了统一串一下。

 

相关文章:

  • 万字长文保姆级教你制作自己的多功能QQ机器人
  • 365天深度学习 | 第7周:咖啡豆识别
  • 深入剖析JavaScript(二)——异步编程
  • 工业智能网关BL110应用之七: 支持 Modbus ,MQTT,opc 等协议,上传到阿里华为云等LOT
  • c和指针-struct结构
  • 计算机网络 二、网络协议
  • 容器编排工具鉴赏- docker-compose 、Kubernetes、OpenShift、Docker Swarm
  • 【论文笔记】—低光图像增强—Supervised—URetinex-Net—2022-CVPR
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • 12c++呵呵老师【变量,定时器和事件】
  • 元宇宙地产演化史:从文本时代到区块链时代
  • Linux搭建开源企业云盘Seafile,私有文件同步云盘及基本使用
  • 【推荐系统】推荐系统基础算法-基于矩阵分解的推荐方法、隐语义模型
  • celery apply_async定时任务重复执行问题
  • 接口测试基本知识点
  • [译]CSS 居中(Center)方法大合集
  • 「译」Node.js Streams 基础
  • exports和module.exports
  • HTTP那些事
  • IndexedDB
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • laravel with 查询列表限制条数
  • MD5加密原理解析及OC版原理实现
  • nodejs实现webservice问题总结
  • Odoo domain写法及运用
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • RxJS: 简单入门
  • SpiderData 2019年2月23日 DApp数据排行榜
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 讲清楚之javascript作用域
  • 聊聊hikari连接池的leakDetectionThreshold
  • 七牛云假注销小指南
  • 前端之Sass/Scss实战笔记
  • #vue3 实现前端下载excel文件模板功能
  • (分类)KNN算法- 参数调优
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (七)Java对象在Hibernate持久化层的状态
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • ./和../以及/和~之间的区别
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .net 发送邮件
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • [ SNOI 2013 ] Quare
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [20150629]简单的加密连接.txt
  • [ANT] 项目中应用ANT
  • [c]扫雷