Java虚拟机学习笔记整理,java面试视频教学

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

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

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

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

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

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

正文

(2)加载该类的ClassLoader已经被回收;

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

满足了上面三个条件也仅仅是“可以”进行回收了,还要根据HotSpot的一些配置参数综合考虑。

什么时候回收?

垃圾收集器在对堆进行回收前,第一件事就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”,对于这些已经“死去”的对象我们需要进行回收。判断对象是否存活的算法:

(1)引用计数算法

算法过程如下:【给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的】。

引用计数算法实现简单,判定效率也很高,大部分情况下是一个不错的算法。但有一个比较重要的缺点:很难解决对象之间相互循环引用的问题。比如:j假设变量objA、objB为某个类的对象实例,objA中持有一个指向objB的成员,此时objB的引用计数为1;在objB中持有一个指向objA的成员,此时objA的引用计数值也为1;此时,即使把objA、objB都置为null,此时两个对象都不能被回收,因为这两个对象虽然为null了,但是它们的引用计数值都还为1。

(2)可达性分析算法

目前主流的虚拟机,如java默认虚拟机HotSpot就是用的这种方式。算法基本思路为:【通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时(或者说从GC Roots到这个对象不可达),则证明此对象是不可用的】。

可作为GC Roots的对象包括:

1)虚拟机栈(栈帧中的本地变量表)中引用的对象;

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

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

4)本地方法栈中JNI(即一般说的Native方法)引用的对象;

需要注意的是,即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过(也就是说对象的finalize()方法只能被调用一次),虚拟机将这两种情况都视为“没有必要执行”。

如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它(即去执行对象的finalize()方法,这里所谓的“执行”是值虚拟机会触发这个方法,但并不承若会等待它运行结束,主要是为了防止对象的finalize方法执行缓慢或发生死循环,导致其他对象不能被执行的,从而引起内存回收系统崩溃)。

finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只需要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。

因此对于不可达对象判定真正死亡的过程小结如下:(1)GC进行第一次标记并进行一次筛选(筛选那些覆盖了finalize方法并且finalize方法是第一次调用的对象);–> (2)另一个低优先级的线程去调用那些被筛选出来的对象的finalize方法;–> (3)GC进行第二次标记,如果在前一步中那些筛选出来的对象没有在finalize拯救自己,此时,那些未被筛选到的和这些这些筛选到的但是没有拯救自己的对象都将会回收。

2、垃圾回收算法

======================================================================

2.1 标记-清除


是最基础的一种收集算法。分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。标记过程就是上面可达性分析算法中所讲的二次标记过程。标记-清除算法的执行过程如下图所示:

回收前状态:

回收后状态:

缺点:

(1)效率问题:标记和清除的两个过程效率都不高;

(2)空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后需要分配较大对象时,无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作;

2.2 复制算法


为了解决上面算法的效率问题,复制算法出现。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存使用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

复制算法的优点:

(1)每次都是对整个半区进行内存回收,实现简单、运行也高效;

(2)在那块使用内存上进行内存分配时,不用考虑内存碎片的问题,只要移动堆顶指针,按顺序分配内存即可;

缺点:

将内存缩小为原来的一半,代价较高。

复制算法的执行过程如下:

回收前的状态:

回收后的状态:

按照新生代的特点,新生代中的对象98%是“朝生夕死”的,因此,可以改进上面的复制算法,目前商业虚拟机正是用这种改进的收集算法来回收新生代。

改进的收集算法:

根据新生代的特点,我们并不需要按照1:1的比例来划分内存空间,而是将内存划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活的对象一次性地复制到另外一块Survivor空间,最后清理掉Eden和刚才用过的Survivor空间,清理完成后,刚刚被清理的Eden和另一块在回收时放入存活对象的Survivor空间作为使用内存,刚被清理的Survivor作为保留空间,以便后面用来回收之用。

这种改进的收集算法也有一个问题,就是在回收时,那块空的Survivor空间能否放得下Eden和使用的Survivor空间中还存活的对象,如果Survivor空间不够存放上一次新生代收集下来的存活对象,此时就需要向老年代“借”内存,那些剩余未放下的对象就通过分配担保机制进入老年代。

2.3 标记-整理算法


复制算法如果在对象存活率较高时,就需要进行较多次的复制操作,效率也会变低。而对于老年代中的对象,一般存活率都较高,因此需要选用其他收集算法:标记 - 整理算法。标记过程仍然与“标记-清除”算法中一样,但是在标记完成后并不直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。算法示意图如下:

回收前状态;

回收后状态:

2.4 分代收集算法


当前商业虚拟机都采用这个“分代收集”算法(Generation Collection),它根据对象存活周期的不同将内存划分为几块,一般是把java堆分为新生代和老年代,根据各个年代的特点选用不同的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,因此可以选用“复制算法”,此时只需要付出少量存活对象的复制成本即可;对于老年代,因为对象存活率较高、也没有额外空间为期分配担保,就必须使用“标记-清除”或“标记-整理”算法来进行回收。

3 垃圾收集器

=====================================================================

如果说上面介绍的收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现,按照上面的介绍,目前垃圾收集器基本都采用分代收集,因此一个垃圾收集器中一般都存在多种垃圾回收算法。不同的虚拟机提供的垃圾收集器也有很大差异,如下是HotSpot虚拟机基于JDK1.7版本所包含的所有垃圾收集器:

HotSpot中共有7中不同的垃圾收集器,如果两个收集器之间存在连线,说明它们之间可以搭配使用,其中,Serial、ParNew、Parallel Scavenge属于新生代收集器,CMS、Serial Old、Parallel Old属于老年代收集器,G1是最新的一种收集器,在新生代和老年代中都可使用。

3.1 Serial(串行)收集器


最基本、发展历史最悠久的一种收集器。看名字就知道,这个收集器是一个单线程的收集器,只使用一个CPU或一条收集线程去完成垃圾收集工作,最重要的是,在它进行垃圾收集的时候,必须暂停其他所有的工作线程,知道它收集结束。虽然有这个缺点,但是依然是虚拟机运行在Client模式下的默认新生代收集器。优点是:简单而高效,没有线程交互的开销。运行过程如图:

新生代采用的是“复制算法”,老年代采用的是“标记-整理”算法。

3.2 ParNew收集器


ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其他行为和Serial收集器一样。ParNew是许多运行在Server模式下的虚拟机中首选的新生代收集器,其中有一个与性能无关的重要原因,除了Serial收集器外,目前只有ParNew能与老年代的CMS收集器配合使用。ParNew是一种并行的收集器。在垃圾回收中,并行是指:多条垃圾收集线程并行工作,用户线程处于等待状态;并发是指:用户线程和垃圾收集线程同时执行(不一定并行,可能交替执行)。

3.3 Parallel Scavenge收集器


读者福利

分享一份自己整理好的Java面试手册,还有一些面试题pdf

不要停下自己学习的脚步

字节跳动的面试分享,为了拿下这个offer鬼知道我经历了什么

字节跳动的面试分享,为了拿下这个offer鬼知道我经历了什么

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

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

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

GR-1713630533091)]

[外链图片转存中…(img-N8dvQ6SL-1713630533091)]

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值