GC相关面试题

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/TTTZZZTTTZZZ/article/details/88106596

GC相关面试题

Object的finalize()方法的作用是否与C++的析构函数作用相同?

与C++的析构函数不同,析构函数确定调用,而它是不确定的

当垃圾回收器宣告一个对象死亡时,至少要经过两次的标记过程,如果对象在可达性分析够发现对象没有与GCRoot连接的引用链,就会被第一次标记。并且判断是否执行finalized()方法,如果对象覆盖finzlize方法并且未被应用过这个对象就会被放置在F-Queue队列中。并在稍后有一个虚拟机建立的一个低优先级的finalize去执行触发finalize方法。由于优先级太低,方法执行随时可能被中止。

finalize方法的作用是为对象提供最后一次逃脱死亡的机会。

由于finalize方法的运行不确定性较大,无法保证各对象的调用顺序。同时运行代价十分高昂,所以不建议使用。

为什么不能显示直接调用finalize方法?

finalize方法在垃圾回收时一定会被执行,而如果在此之前显示执行的话,也就是说finalize会被执行两次以上,而在第一次资源已经被释放,那么在第二次释放资源时系统一定会报错,因此一般finalize方法的访问权限和父类保持一致,为protected。

Java中的强引用,软引用,弱引用,虚引用有什么用?

强引用(Strong Reference):

  1. 最普遍的引用:Object obj = new Object();
  2. 当对象为强引用时,并且内存不足时,Java宁可抛出OOM异常也不会回收具有强引用的对象。
  3. 如果我们不实用这个对象了,我们可以通过将对象设置为Null来弱化引用,使其被回收。或者等待超出它的生命周期范围。这时GC就会认为不存在该对象的引用,就会将其回收。

软引用(Soft Reference):

  1. 对象处于有用但非必须状态

  2. 只有当内存空间不足时,GC会回收该引用的对象的内存

  3. 可以用软引用来实现高速缓存

  4. String str = new String("abc"); // 强引用

    SoftReference<String> softref = new SoftReference<String>(str); // 软引用

弱引用(Weak Reference):

  1. 非必须的对象,比弱引用更弱一些

  2. GC时会被回收

  3. 被回收的概率也不大,因为GC的线程优先级比较低

  4. 适用于引用偶尔被使用且不影响垃圾收集机制的对象

  5. String str = new String("abc"); // 强引用

    WeakReference<String> weakref = new WeakReference<String>(str); // 软引用

虚引用(PhantomReference):

  1. 不会决定对象的生命周期

  2. 任何时候都可能被垃圾回收器回收

  3. 跟踪对象被垃圾收集器回收的活动,其哨兵作用

  4. 必须和应用队列ReferenceQueue联合使用

  5. String str = new String("abc");
    RegerenceQueue queue = new RegerenceQueue();
    PhantomReference ref = new PhantomReference(str,queue);
    

在这里插入图片描述

GC是在什么时候,对什么东西,做了什么事情?

什么时候

  1. 系统自身决定,不可预测的时间/调用System.gc()的时候。
  2. 新生代、老年代结构,提出minor gc/full gc
  3. 说明minor gc/full gc的触发条件、OOM的触发条件,降低GC的调优的策略。
  4. eden满了minor gc,升到老年代的对象大于老年代剩余空间full gc,或者小于时被HandlePromotionFailure参数强制full gc;gc与非gc时间耗时超过了GCTimeRatio的限制引发OOM,调优诸如通过NewRatio控制新生代老年代比例,通过 MaxTenuringThreshold控制进入老年前生存次数等

总结:程序员不能具体控制时间,系统在不可预测的时间调用System.gc()函数的时候;当然可以通过调优,用NewRatio控制newObject和oldObject的比例,用MaxTenuringThreshold 控制进入oldObject的次数,使得oldObject 存储空间延迟达到full gc,从而使得计时器引发gc时间延迟OOM的时间延迟,以延长对象生存期。

对什么东西?

  1. 从gc root开始搜索,搜索不到的对象
  2. 从root搜索不到,而且经过第一次标记、清理后,仍然没有复活的对象

总结:超出了作用域或引用计数为空的对象;从gc root开始搜索找不到的对象,而且经过一次标记、清理,仍然没有复活的对象。

做什么?

  1. 删除不使用的对象,腾出内存空间。
  2. 停止其他线程执行、运行finalize等
  3. 新生代做的是复制清理、from survivor、to survivor是干啥用的、老年代做的是标记清理、标记清理后碎片要不要整理、复制清理和标记清理有有什么优劣势
  4. 清楚串行、并行(整理/不整理碎片)、CMS等搜集器可作用的年代、特点、优劣势,并且能说明控制/调整收集器选择的方式。

总结:删除不使用的对象,回收内存空间;运行默认的finalize,当然程序员想立刻调用就用dipose调用以释放资源如文件句柄,JVM用from survivor、to survivor对它进行标记清理,对象序列化后也可以使它复活。

Java虚拟机规范将JVM虚拟机所管理的内存分为几部分?

img

  1. 程序计数器(Program Counter Register)

是一块较小的内存空间,它的作用可以看做是当前线程所执行字节码的行号指示器。是线程私有,生命周期与线程相同。

  1. Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。

Java虚拟机栈描述的是Java方法(区别于native的本地方法)执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动作链接、方法出口等信息。每个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

  1. 本地方法栈(Native Method Stacks)

与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机所使用到的Native方法服务。

  1. 方法区

有哪些方法可以判断一个对象已经可以被回收,JVM怎么判断一个对象已经消亡可以被回收?

①引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1;当引用失效时,计数器值就减1;任何时刻计数器都为0的对象就是不可能再被使用的。
Java语言没有选用引用计数法来管理内存,因为引用计数法不能很好的解决循环引用的问题。
②根搜索算法
在主流的商用语言中,都是使用根搜索算法来判定对象是否存活的。
GC Root Tracing 算法思路就是通过一系列的名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连,即从GC Roots到这个对象不可达,则证明此对象是不可用的。

img

比如上图,左边的对象都是存活的,右边的都是可以回收的。

哪些对象可以作为GC Roots?

  1. 虚拟机栈(栈帧中的本地变量表)中的引用的对象
  2. 方法区中的类静态属性引用的对象
  3. 方法区中的常量引用的对象
  4. 本地方法栈中JNI(Native方法)的引用对象

猜你喜欢

转载自blog.csdn.net/TTTZZZTTTZZZ/article/details/88106596