JVM(三)—— 垃圾收集器与内存分配策略

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43635659/article/details/102712087

垃圾收集器与内存分配策略

3.1 概述

  • 垃圾收集器(GC)是比Java语言更早的出现。
  • 对于Java虚拟机运行时数据区的程序计数器、虚拟机栈和本地方法栈是线程私有的,也就是说是随着线程的创建而创建,随线程的销毁而销毁,所以它们属于自动垃圾回收。对于Java堆和方法区(非堆,老年代)是线程共享的,随着虚拟机的启动而创建,所以需要进行垃圾回收。

3.2 对象的死亡

  • 判断对象是否还活着可以使用引用计数算法和可达性分析算法。

3.2.1 引用计数算法

  • 原理:每创建一个对象,就给这个对象关联一个计数器,如果对象被引用一次,计数器就加1,对象引用失效,计数器就减1,当计数器的值为0时,就代表当前对象是不可用的。(注意此时对象并不是死了,还需要两次标记过程)
  • 缺点:如果两个对象循环引用,那么此种方法就失效了。

3.2.2 可达性分析算法

  • 原理:从一个称为GC Roots的对象作为起始点,然后向下进行搜索,搜索经过的路径叫做引用链,当一个对象到GC Roots没有任何引用链相连,则此对象是不可用的。(注意此时对象并不是死了,还需要两次标记过程)
  • 可以作为GC Roots对象:
    • 虚拟机栈(局部变量表)reference类型引用的对象。
    • 方法区中类变量应用的对象(static String str = new String())
    • 方法区中常量引用的对象(String str = new String(“123”))
    • 本地方法栈JNI(Native方法)引用的对象

3.2.3 四种引用

  • 传统的引用定义:对于reference类型的值代表的是一块内存的起始地址,那么这块内存就代表一个引用。
  • JDK1.2之后引入了四种引用:强引用、软引用、弱引用、虚引用。
    • 强引用:在Java程序中最普遍,形如“Object obj = new Object()”这种就是强引用,只要是强引用还在,垃圾收集器就不会对其回收。
    • 软引用:软引用是用来描述一些有用但非必需的对象。对于软引用关联着的对象,在内存溢出将要发生之前,对此类对象进行第二次垃圾回收。如果此时内存还是不够,才会抛出内存溢出异常。通过SoftReference类来实现。
    • 弱引用:弱引用也是用来描述一些非必需的对象。对于弱引用关联着的对象,在第二次垃圾回收的时候对其进行回收,不管内存够不够(会不会发生内存溢出)。通过WeakReference类来实现。
    • 虚引用:又叫做幽灵引用或者是幻影引用。它是和对象关联最弱的一种引用,并不能通过此类引用创建对象实例,唯一的作用是标记对象在对象被回收的时候收到一个系统通知。可以通过PhantomRefenrence类来实现。

3.2.4 对象死亡的两次标记过程

  • 之前的引用计数算法和可达性分析算法判断对象是否还可用,要判断对象是否死亡还需要经过两次标记过程。
  • 第一次标记:
    • 如果对象对象在可达性分析之后没有到达GC Roots的引用链,那么将会被第一次标记并进行一次筛选,筛选的条件是此对象是否有必要执行finalize方法。当对象没有覆盖finalize方法或者是虚拟机的finalize方法已经执行,那么对象将没有必要执行finalize方法。对象死亡。
  • 第二次标记:
    • 如果判定对象有必要执行finalize方法,那么这个对象会放置在一个F-Queue队列中,并在稍后虚拟机自动创建的、低优先级的Finalizer线程去执行它。finalize方法是对象逃脱标记的唯一机会,稍后GC 将对F-Queue队列中的对象进行二次小规模的标记,如果此时对象想拯救自己——只需要重新与引用链中的任何一个对象建立关联即可。比如把自己(this)赋值给类变量或者对象的成员变量。此时将会移除标记队列。对象成功逃脱。否则对象死亡。

猜你喜欢

转载自blog.csdn.net/weixin_43635659/article/details/102712087
今日推荐