首页 > 其他分享 >JVM学习笔记2——垃圾回收GC

JVM学习笔记2——垃圾回收GC

时间:2023-08-08 18:34:24浏览次数:42  
标签:对象 list System 笔记 GC 引用 JVM new out

三、垃圾回收

 

1.如何判断对象是否可以回收

 

①引用计数法——早期python中使用

当一个对象被引用时,就当引用对象的值加一,当值为 0 时,就表示该对象不被引用,可以被垃圾收集器回收。
这个引用计数法听起来不错,但是有一个弊端,如下图所示,循环引用时,两个对象的计数都为1,导致两个对象都无法被释放。

 

 

 

②可达性分析算法——JVM使用

VM 中的垃圾回收器通过可达性分析来探索所有存活的对象
扫描堆中的对象,看能否沿着 GC Root 对象为起点的引用链找到该对象,如果找不到,则表示可以回收


可以作为 GC Root 的对象有:

Ⅰ. 虚拟机栈(栈帧中的本地变量表)中引用的对象;

Ⅱ. 方法区中类静态属性引用的对象;

Ⅲ. 方法区中常量引用的对象;

Ⅳ. 本地方法栈中 JNI(即一般说的Native方法)引用的对象;

 

 

案例演示:

public static void main(String[] args) throws IOException {

        ArrayList<Object> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add(1);
        System.out.println(1);
        System.in.read();

        list = null;
        System.out.println(2);
        System.in.read();
        System.out.println("end");
    }

对于以上代码,可以使用如下命令将堆内存信息转储成一个文件,然后使用
Eclipse Memory Analyzer 工具进行分析。


第一步:
使用 jps 命令,查看程序的进程

 

第二步:

使用 jmap -dump:format=b,live,file=1.bin 16104 命令转储文件
dump:转储文件
format=b:二进制文件
file:文件名
16104:进程的id

 

第三步:打开 Eclipse Memory Analyzer 对 1.bin 文件进行分析。

分析的 gc root,找到了 ArrayList 对象,然后将 list 置为null,再次转储,那么 list 对象就会被回收

 

 

 

 

③四种引用

强引用:

只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收

 

软引用(SoftReference):

仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次出发垃圾回收,回收软引用对象,可以配合引用队列来释放软引用自身

 

弱引用(WeakReference):

仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象,可以配合引用队列来释放弱引用自身

 

虚引用(PhantomReference):

必须配合引用队列使用,主要配合 ByteBuffer 使用,被引用对象回收时,会将虚引用入队,由 Reference Handler 线程调用虚引用相关方法释放直接内存

 

终结器引用(FinalReference):

无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize 方法,第二次 GC 时才能回收被引用对象。

 

 

Ⅰ.软引用&引用队列案例演示——SoftReference

/**
 * 演示 软引用
 * -Xmx20m -XX:+PrintGCDetails -verbose:gc
 */
public class Code_08_SoftReferenceTest {

    public static int _4MB = 4 * 1024 * 1024;

    public static void main(String[] args) throws IOException {
        method2();
    }

    // 强引用,设置 -Xmx20m , 演示堆内存不足,
    public static void method1() throws IOException {
        ArrayList<byte[]> list = new ArrayList<>();

        for(int i = 0; i < 5; i++) {
            list.add(new byte[_4MB]);
        }
        System.in.read();
    }

    // 演示 软引用
    public static void method2() throws IOException {
        ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
        for(int i = 0; i < 5; i++) {
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }
        System.out.println("循环结束:" + list.size());
        for(SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }
}

 

 method1 方法解析:

首先会设置一个堆内存的大小为 20m,然后运行 mehtod1 方法,会抛异常,堆内存不足,因为 mehtod1 中的 list 都是强引用

 

 method2 方法解析:

在 list 集合中存放的是软引用对象,当内存不足时,会触发 full gc,将软引用的对象回收。细节如图:

可以看到第五次循环时发现内存不足,触发了垃圾回收,将前4个软引用对象全部回收;

 

 

 

 上面的代码中,当软引用引用的对象被回收了,但是软引用还存在,所以,一般软引用需要搭配一个引用队列一起使用。

修改 method2 如下:

// 演示 软引用 搭配引用队列
    public static void method3() throws IOException {
        ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
        // 引用队列
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        for(int i = 0; i < 5; i++) {
            // 关联了引用队列,当软引用所关联的 byte[] 被回收时,软引用自己会加入到 queue 中去
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }

        // 从队列中获取无用的 软引用对象,并移除
        Reference<? extends byte[]> poll = queue.poll();
        while(poll != null) {
            list.remove(poll);
            poll = queue.poll();
        }

        System.out.println("=====================");
        for(SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }

 此时已经为空的软引用本身也被移除了,输出结果如下:

 

 

 Ⅱ.弱引用案例演示——WeakReference

弱引用
 public class Code_09_WeakReferenceTest {

    public static void main(String[] args) {
//        method1();
        method2();
    }

    public static int _4MB = 4 * 1024 *1024;

    // 演示 弱引用
    public static void method1() {
        List<WeakReference<byte[]>> list = new ArrayList<>();
        for(int i = 0; i < 10; i++) {
            WeakReference<byte[]> weakReference = new WeakReference<>(new byte[_4MB]);
            list.add(weakReference);

            for(WeakReference<byte[]> wake : list) {
                System.out.print(wake.get() + ",");
            }
            System.out.println();
        }
    }

    // 演示 弱引用搭配 引用队列
    public static void method2() {
        List<WeakReference<byte[]>> list = new ArrayList<>();
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        for(int i = 0; i < 9; i++) {
            WeakReference<byte[]> weakReference = new WeakReference<>(new byte[_4MB], queue);
            list.add(weakReference);
            for(WeakReference<byte[]> wake : list) {
                System.out.print(wake.get() + ",");
            }
            System.out.println();
        }
        System.out.println("===========================================");
        Reference<? extends byte[]> poll = queue.poll();
        while (poll != null) {
            list.remove(poll);
            poll = queue.poll();
        }
        for(WeakReference<byte[]> wake : list) {
            System.out.print(wake.get() + ",");
        }
    }

}

 

 

 

 

 

 2.垃圾回收算法

 

 ①标记清除Mark Sweep

对于没有被GC Root引用的对象做标记,然后直接清除

优点:速度较快

缺点:会产生内存碎片

 

 

 

 ②标记整理Mark Compact

对于有被GC Root引用的对象做标记并将其移动到连续内存空间中,其它全部清除

 

优点:没有内存碎片

缺点:速度慢

 

 

 ③复制Copy

将内存空间分为两部分FROM和TO,只在FROM区域存放对象,垃圾回收时先将有被GC Root引用的对象做标记并复制到TO区域中,

然后清除FROM区域的全部数据,最后让FROM和TO区域互换身份

 

优点:没有内存碎片

缺点:需要占用两倍内存空间

 

 

 

 

 

3.分代垃圾回收

 

标签:对象,list,System,笔记,GC,引用,JVM,new,out
From: https://www.cnblogs.com/AvavaAva/p/17614648.html

相关文章

  • java springcloud 大文件分片上传处理
    ​ 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。先说下要求:PC端全平台支持,要求支持Windows,Mac,Linux支持所有浏览器。支持文件批量上传支持文件夹上传,且要求在服务端保留层级结构。文件夹数量要求支持到10W......
  • JVM学习之:堆(Heap)和非堆(Non-heap)内存
    JVM学习之:堆(Heap)和非堆(Non-heap)内存 堆(Heap)和非堆(Non-heap)内存:堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在Java虚拟机启动时创建的。“在JVM中堆之外的内存称为非堆内存(Non-heapmemory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来......
  • SpringCloud
     1.微服务技术栈有哪些1.1微服务条目 1.2各大IT公司微服务架构阿里:Dubbo+HFS京东:JSF新浪:Motan当当:DubboX1.3各微服务框架对比  1.4网站架构图 1.5SpringCloudvsDubbo  1.6参考文档SpringCloudNetflix中文文档参考手册中文版Spring......
  • 树状数组学习笔记
    树状数组作为一个常数小且好写的数据结构,虽然功能没有线段树那么齐全,但是其中的扩展内容还是很多的。维护区间和1.0BIT的作用树状数组可以做到单次logn求前缀和,单次logn修改信息维护一个前缀和。1.1区间修改单点查询考虑维护差分数组\(c[i]=a[i]-a[i-1]\)。在查询......
  • C语言学习笔记(八)指针详解
    指针详解arr[i]=*(arr+i)=*(p+i)=p[i]字符指针charp*intmain(){ charch='w'; char*pc=&ch; return0;}intmain(){ chararr[]="abcdefg"; char*pc=arr; printf("%s\n",arr); printf("%s\n",pc); ......
  • 论文解读(LightGCL)《LightGCL: Simple Yet Effective Graph Contrastive Learning for
    Note:[wechat:Y466551|可加勿骚扰,付费咨询]论文信息论文标题:LightGCL:SimpleYetEffectiveGraphContrastiveLearningforRecommendation论文作者:Cai,XuhengandHuang,ChaoandXia,LianghaoandRen,Xubin论文来源:2023ICLR论文地址:download 论文代码:download视......
  • C++STL 学习笔记
    C++STL学习笔记STL补充List链表list<int>mylist={}链表定义和初始化voidpush_front(constT& val)将val插入链表最前面voidpop_front()删除链表最前面的元素list.push_back() 增加一个新的元素在list的尾端list.pop_back() 删除list的......
  • 【学习笔记】【数学】计算几何基础
    点击查看目录目录前置知识:叉积与跨立实验前置知识:建议虽然是简单的前置知识,还是打开略过一遍。浮点数与误差分析(少用除法)向量相关向量向量,就是带有方向和大小两个属性的边,通常形式为\(\overrightarrow{AB}=(a_1,a_2)=A\)。运算与性质:判等:两点坐标重合。ilint......
  • C语言听课笔记
    %1f——double;%c——char;%p——&a;%s——char[]求两个数的较大值#include<stdio.h>int main(){ int num1=10; int num2=20; if (num1>num2)    printf("较大值是:%d\n",num1); else    printf("较大值是:%d\n",num2); return 0;}#include<stdio.h&......
  • PyTorch基础知识-新手笔记
    使用NumPy实现机器学习任务使用最原始的的NumPy实现一个有关回归的机器学习任务,不使用PyTorch中的包或类。代码可能会多一点,但每一步都是透明的,有利于理解每一步的工作原理。主要步骤如下:1)首先,给出一个数组x,然后基于表达式y=3x^2+2,加上一些噪声数据到达另一组数据。2)然后,构建......