【JVM系列8】JVM经典面试问题(内存溢出和内存泄露)解答及调优实战分析(1)

  • 1、Java虚拟机已经调用过当前对象的finalize()方法

  • 2、finalize()方法被我们重写了

如果不满足这两种情况,那么对象就相当于是“死刑立即执行”,没有机会逃生,但是一旦满足执行finalize()方法的条件,而我们又在finalize()方法中将对象重新和引用链中的对象进行了关联,这时候对象就可以顺利“逃生”。

我们来看下面一个例子:

package com.zwx.jvm;

import java.util.ArrayList;

import java.util.List;

public class ObjEscapeByFinalize {

public static ObjEscapeByFinalize objEscapeByFinalize = null;

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

objEscapeByFinalize = new ObjEscapeByFinalize();

//首次自救

objEscapeByFinalize = null;

System.gc();

Thread.sleep(1000);//finalize()方法优先级比较低,稍微停顿一会等一等

print();

//再次自救

objEscapeByFinalize = null;

System.gc();

Thread.sleep(1000);

print();

}

static void print(){

if (null == objEscapeByFinalize){

System.out.println(“obj has been gc”);

}else{

System.out.println(“obj escape success”);

}

}

@Override

protected void finalize() throws Throwable {

System.out.println(“come in method:finalize”);

super.finalize();

objEscapeByFinalize = this;

}

}

运行结果为:

come in method:finalize

obj escape success

obj has been gc

从结果可以看到,第一次自救成功,而第二次已经没有了自救机会,因为当前对象已经执行过一次finalize()方法了,而如果我们把finalize()方法中的:

objEscapeByFinalize = this;

替换为:

objEscapeByFinalize = new ObjEscapeByFinalize();

这时候就可以一直自救成功,因为每次自救之后就产生了一个新的对象,新的对象并没有执行过finalize()方法。

上面的demo还有一点需要注意的是,finalize()方法针对的是对象,假如上面的静态对象换成一个其他对象,而finalize()方法又写在当前对象,那么是无效的,例如如下例子:

package com.zwx.jvm;

import java.util.ArrayList;

import java.util.List;

public class ObjEscapeByFinalize1 {

public static List list = null;

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

list = new ArrayList<>();

//首次自救

list = null;

System.gc();

Thread.sleep(1000);

print();

}

static void print(){

if (null == list){

System.out.println(“obj has been gc”);

}else{

System.out.println(“obj escape success”);

}

}

@Override

protected void finalize() throws Throwable {

System.out.println(“come in method:finalize”);

super.finalize();

list = new ArrayList<>();

}

}

这里是无法实现自救的,因为这里要救的对象是List,而finalize()并不属于List,是属于ObjEscapeByFinalize1对象,所以这一点也是需要明确地。

不过虽然finalize()可以完成对象自救,但是由于这个方法的代价比较大而且运行时有不确定性,一般情况下还是不建议使用

4、Young GC会有STW吗


不管是什么类型的GC,都会有 stop-the-world,只是发生时间的长短,目前Java中所有的垃圾回收器均需要STW,唯一的区别只是时间的长短问题。

5、Major GC和Full GC的区别


之前我们提到了,Major GC通常会伴随着Minor GC,也就等于触发了Full GC,但是虽然如此,Major GC和Full GC并不是完全等价的,因为Full GC 的同时会对方法区(jdk1.8的metaspace,jdk1.7的永久代)进行GC,所以严格来说:Full GC=Major GC+Minor GC+方法区GC

6、方法区会发生GC吗


答案是肯定的。虽然方法区中的回收收益一般都不高,但是也是会被GC的,而方法区中被回收的最主要的就是对废弃常量无用类的回收,判定一个废弃常量比较简单,但是判定一个类是无用类是比较困难的,那么方法区中的怎么判断一个类是无用类呢?

判断一个类是否无用,需要达到以下三个条件:

  • 1、该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。

  • 2、加载该类的类加载器ClassLoader已经被回收(从这个条件可以看出,一般只有大量使用了反射,动态代理或者字节码框架等场景条件下才会满足这个条件)。

  • 3、该类对应的 java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

这三个条件实际上是非常苛刻的,而即使达到以上三个条件,无用类也仅仅是可以被回收,但是是不是一定会被回收,还是取决于Java虚拟机。HotSpot虚拟机中提供了参数-Xnoclassgc来控制。

7、什么是直接内存


直接内存(Direct Memory)不属于运行时数据区,也被称之为堆外内存,通常访问直接内存的速度会优于Java堆。直接没存也有可能会发生OutOfMemoryError异常,Java 1.4中新加入的nio包下的ByteBuffer就操作了直接内存,直接内存可以通过参数-XX:MaxDirectMemorySize控制大小。

8、CMS收集器和G1收集器的区别


作为同样是并行的2款垃圾收集器,G1的目前是用来取代CMS收集器的,其主要有如下区别:

  • 1、CMS收集器是老年代的收集器,需要和其他新生代收集器配合使用,而G1同时适用于新生代和老年代,不需要和其他收集器配合使用

  • 2、CMS收集器以最小的停顿时间为目标的并发收集器,G1收集器是一种可预测垃圾回收的停顿时间

  • 3、CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片,G1使用了 Region方式对堆内存进行了划分,且基于标记整理算法实现,整体减少了垃圾碎片的产生

9、类加载机制经过哪些步骤


类加载机制主要经过了:加载(Loading)连接(Linking)初始化(Initialization)使用(Using)卸载(Unloading) 五个大阶段,而其中连接(Linking)又分为:验证(Verification),准备(Preparation),**解析(Resolution)**三个阶段。想要详细了解每个阶段做了什么事情,可以点击这里

10、系统CPU经常100%,如何定位


  • 1、首先要确认哪个进程占用CPU高,可以使用top命令

在这里插入图片描述

  • 2、找到之后可以继续执行top -Hp PID命令查询出占用最大的线程

在这里插入图片描述

  • 3、执行jstack命令生成线程快照信息:

jstack -l 进程PID >jstack.log

输出之后,我们找到上面占用CPU最高的一个线程pid=11566,将其转换为16进制,得到的结果是2d2e,然后进入生成的jstack.log文件找到这个线程可以查看线程信息。

在这里插入图片描述

更多:Java进阶核心知识集

包含:JVM,JAVA集合,网络,JAVA多线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等

image

高效学习视频

rk,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3eDkwMDEwMg==,size_16,color_FFFFFF,t_70#pic_center)

更多:Java进阶核心知识集

包含:JVM,JAVA集合,网络,JAVA多线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等

[外链图片转存中…(img-M2QQOOHT-1714513714995)]

高效学习视频

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值