【备战秋招冲击大厂】Java面试题系列—JVM及垃圾回收机制(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

4. JVM 调优,查看 JVM 参数默认值

  • jps -v 可以查看 jvm 进程显示指定的参数

  • 使用 -XX:+PrintFlagsFinal 可以看到 JVM 所有参数的值

  • jinfo 可以实时查看和调整虚拟机各项参数

  • jstat -gc 12538 5000即会每5秒一次显示进程号为12538的java进程的GC情况

5. OOM排查方法

1)先查看应用进程号pid:ps -ef | grep 应用名

2)查看pid垃圾回收情况: jstat -gc pid 5000(时间间隔)

3)开启OOM快照:

-XX:+HeapDumpOnOutOfMemoryError(开启堆快照)

-XX:HeapDumpPath=C:/m.hprof(保存文件到哪个目录)

4)dump 查看方法栈信息:jstack -l pid > /home/test/jstack.txt

5)dump 查看JVM内存分配以及使用情况:jmap -heap pid > /home/test/jmapHeap.txt

6)dump jvm二进制的内存详细使用情况

6. 类加载

  • 类加载器:

  • 类加载过程:加载,验证,准备,解析,初始化

  • 加载:加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的入口。

  • 验证:确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

  • 准备:准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。

  • 解析:解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。

  • 初始化:初始化阶段是执行类构造器方法的过程。到了初始阶段,才开始真正执行类中定义的Java程序代码。

  • 双亲委派模型

  • 定义:除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器,这里类加载器之间的父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)的关系实现。

  • 工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器,每一个层次的加载器都是如此,依次递归,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成此加载请求(它搜索范围中没有找到所需类)时,子加载器才会尝试自己加载。

  • 优点:使用双亲委派模型来组织类加载器之间的关系,使得Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放再rt.jar中,无论哪个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。

  • 打破双亲委派机制的方法:重写loadclass()方法

  • 打破双亲委派机制的例子:

  • Tomcat,应用的类加载器优先自行加载应用目录下的 class,并不是先委派给父加载器,加载不了才委派给父加载器。打破的目的是为了完成应用间的类隔离。

  • JDK 9,Extension ClassLoader 被 Platform ClassLoader 取代,当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载。打破的原因,是为了添加模块化的特性。

  • 沙箱安全机制:防止恶意代码污染java源代码。

7. JVM加载class文件的原理

JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件的类。

Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。

类装载方式,有两种

  • 隐式装载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中

  • 显式装载,通过class.forname()等方法,显式加载需要的类,隐式加载与显式加载的区别:两者本质是一样的。

Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。

8. GC Roots

作为GCRoots的对象包括下面几种:

1)虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。

2)方法区中的类静态属性引用的对象。

3)方法区中常量引用的对象。

4)本地方法栈中JNI(Native方法)引用的对象。

9. 对象可达性分析

  • 如果对象在进行可达性分析后发现没有与GCRoots相连的引用链,则该对象被第一次标记并进行一次筛选,筛选条件为是否有必要执行该对象的finalize方法,若对象没有覆盖finalize方法或者该finalize方法是否已经被虚拟机执行过了,则均视作不必要执行该对象的finalize方法,即该对象将会被回收。反之,若对象覆盖了finalize方法并且该finalize方法并没有被执行过,那么,这个对象会被放置在一个叫F-Queue的队列中,之后会由虚拟机自动建立的、优先级低的Finalizer线程去执行,而虚拟机不必要等待该线程执行结束,即虚拟机只负责建立线程,其他的事情交给此线程去处理。

  • 对F-Queue中对象进行第二次标记,如果对象在finalize方法中拯救了自己,即关联上了GCRoots引用链,如把this关键字赋值给其他变量,那么在第二次标记的时候该对象将从“即将回收”的集合中移除,如果对象还是没有拯救自己,那就会被回收。

10. 垃圾回收机制

堆分为新生代和老年代,新生代默认占总空间的 1/3,老年代默认占 2/3。新生代使用复制算法,有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1。

当新生代中的 Eden 区内存不足时,就会触发 Minor GC,过程如下:

1)在 Eden 区执行了第一次 GC 之后,存活的对象会被移动到其中一个 Survivor 分区;

2)Eden 区再次 GC,这时会采用复制算法,将 Eden 和 from 区一起清理,存活的对象会被复制到 to 区;

3)移动一次,对象年龄加 1,对象年龄大于一定阀值会直接移动到老年代

4)Survivor 区相同年龄所有对象大小的总和 > (Survivor 区内存大小 * 目标使用率)时,大于或等于该年龄的对象直接进入老年代。其中这个使用率通过 -XX:TargetSurvivorRatio 指定,默认为 50%

5)Survivor 区内存不足会发生担保分配

6)年龄超过指定大小的对象可以直接进入老年代

7)Major GC,指的是老年代的垃圾清理,但并未找到明确说明何时在进行Major GC

8)FullGC,整个堆的垃圾收集,触发条件:

  • 每次晋升到老年代的对象平均大小>老年代剩余空间

  • MinorGC后存活的对象超过了老年代剩余空间

  • 元空间不足

  • System.gc()

  • CMS GC异常,promotion failed:MinorGC时,survivor空间放不下,对象只能放入老年代,而老年代也放不下造成;concurrent mode failure:GC时,同时有对象要放入老年代,而老年代空间不足造成

  • 堆内存分配很大的对象

11. 垃圾回收算法

  • 引用计数法:给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1;当引用失效时,计数器值-1。任何时刻计数值为0的对象就是不可能再被使用的。

  • 缺点:(1)每次给对象赋值时都要维护引用计数器,且计数器本身也有一定的消耗;(2)较难处理循环引用

  • 复制算法:(年轻代)

  • 优点:(1)不产生内存碎片;(2)速度快

  • 缺点:浪费10%的内存空间

  • 标记清除算法(老年代):先标记出要回收的对象,然后统一回收这些对象

  • 优点:节省空间

  • 缺点:产生内存碎片;

  • 标记整理算法(老年代):先标记清除,再次扫描并往一端滑动存活对象。

  • 优点:不产生内存碎片;

  • 缺点:需要移动对象的成本,耗时严重

12. 垃圾收集器

1)Serial收集器:新生代收集器,使用停止复制算法,使用一个线程进行GC,其它工作线程暂停。使用-XX:+UseSerialGC可以使用Serial+Serial Old模式运行进行内存回收(这也是虚拟机在Client模式下运行的默认值)

2)Serial Old收集器:老年代收集器,单线程收集器,使用标记整理(整理的方法是Sweep(清理)和Compact(压缩),清理是将废弃的对象干掉,只留幸存的对象,压缩是将移动对象,将空间填满保证内存分为2块,一块全是对象,一块空闲)算法,使用单线程进行GC,其它工作线程暂停(注意,在老年代中进行标 记整理算法清理,也需要暂停其它线程),在JDK1.5之前,Serial Old收集器与ParallelScavenge搭配使用。

感受:

其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。

特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。

也祝愿各位同学,都能找到自己心动的offer。

分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档

拿到字节跳动offer后,简历被阿里捞了起来,二面迎来了P9"盘问"

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

[外链图片转存中…(img-TVrjZBCA-1713439270523)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-BdtN7K5m-1713439270524)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值