jvm 判断对象是否为垃圾

jvm 判断是否垃圾的算法
1.程序计数器(可能出现重复引用,循环引用)
从而衍生出可达性算法 gc roots
2.可达性分析是JVM垃圾回收中确定垃圾的一种方式。另一种方法为引用记数法,但是引用记数法无法解决循环引用问题。

public class Main {
    
    
    public static void main(String[] args) {
    
    
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
 
        object1.object = object2;
        object2.object = object1;
 
        object1 = null;
        object2 = null;
 
        //最后面两句将object1和object2赋值为null,也就是说object1和object2指向的对象已经不可能再被访问,但是由于它们互相引用对方,导致它们的引用计数都不为0,那么垃圾收集器就永远不会回收它们。
    }
}
 
class MyObject{
    
    
    public Object object = null;
}

在Java语言中,可作为GC Roots的对象包含以下几种:
在这里插入图片描述

虚拟机栈(栈帧中的本地变量表)中引用的对象。(可以理解为:引用栈帧中的本地变量表的所有对象)
方法区中静态属性引用的对象(可以理解为:引用方法区该静态属性的所有对象)
方法区中常量引用的对象(可以理解为:引用方法区中常量的所有对象)
本地方法栈中(Native方法)引用的对象(可以理解为:引用Native方法的所有对象)

2.finalze

对象自我拯救,当对象由可达性变为不可达时,先变成恢复状态,此时可能回去调用finalize方法
1.子类必须重新该方法
2.该方法至多只能被执行一次
且满足以上两种情况——–》底层的finalizer线程执行情况
finalize()方法最终判定对象是否存活:

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历再次标记过程。
标记的前提是对象在进行可达性分析后发现没有与GC Roots相连接的引用链。

1).第一次标记并进行一次筛选。

  筛选的条件是此对象是否有必要执行finalize()方法。
  当对象没有覆盖finalize方法,或者finzlize方法已经被虚拟机调用过,虚拟机将这两种情况 都视为“没有必要执行”,对象被回收。

2).第二次标记

如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个名为:F-Queue的队列之中,并在稍后由一条虚拟机自动建立的、低优先级的Finalizer线程去执行。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束。这样做的原因是,如果一个对象finalize()方法中执行缓慢,或者发生死循环(更极端的情况),将很可能会导致F-Queue队列中的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃。
Finalize()方法是对象脱逃死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()中成功拯救自己----只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出“即将回收”的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了。

1.7后 1.7取消永久代 改成元空间

  • 堆的新生代
    Eden : to survivor : from survivor ==8:1:1
    Eden-> to survivor -> from survivor 过程中不断垃圾回收,然后复制到下一区域,from survivor到 to survivor 称之为一岁,过程不断循环,直到达到15岁,还没有被回收的对象会进入年老区,当Eden区区间用完时,会触发垃圾回收,存活的移到1(to survivor)区 )
    新生代垃圾回收算法是 minorGc
  • 老年代与新生代的比例是 2:1
    年老代的垃圾算法为标记整理和标记清除 (fullGc)
  • Major GC 是清理永久代 ,永久代在1.8取消
    元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制(具体不太清楚)
  • 方法区和堆 是 线程共享的

jvm 内存

jvm 内存默认大小是本地内存的1/64 ,最大尝试使用内存为本地内存的1/4

https://blog.csdn.net/qq_38905818/article/details/102500173

猜你喜欢

转载自blog.csdn.net/qq_38893133/article/details/103882132