写点什么

这套 JVM 核心知识你要全都会,月薪还不过 18K 可以直接跳槽了

用户头像
小Q
关注
发布于: 2020 年 11 月 17 日

应粉丝强烈要求,除了面试经验,还要霸哥多分享一些常见的面试技术点。



刚好前段时间得到了一份关于Java的核心面试知识点的PDF文件,经过整理,然后现在拆分成专题进行分享。



这篇介绍JVM相关核心面试知识点,如果说,Java基础和集合是进入Java开发的基石,那么JVM则是打开进一步打开Java开发大门的钥匙。



下面这套JVM知识能够掌握下来,月薪18K完全没问题,霸哥这里所说的不是精通,能够精通这套JVM体系,当然自会更高。



JVM核心知识点



  • 线程

  • JVM内存区域

  • JVM运行时内存

  • 垃圾回收与算法

  • Java四种应用类型

  • GC分代收集算法VS分区收集算法

  • GC垃圾收集器

  • Java IO/NIO

  • JVM类加载机制



更多高清完整大图,PDF资料,技术视频,关注公众号:Java架构师联盟,后台回复java即可查看获取方式





私信【Java】获取高清完整大图



基本概念:



JVM 是可运行Java代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收,堆和一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接的交互。





运行过程:



我们都知道 Java 源文件,通过编译器,能够生产相应的.Class 文件,也就是字节码文件,而字节码文件又通过 Java 虚拟机中的解释器,编译成特定机器上的机器码 。



也就是如下:



① Java 源文件—->编译器—->字节码文件

② 字节码文件—->JVM—->机器码



每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是 Java 为什么能够跨平台的原因了,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会存在多个虚拟机实例。程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不能共享。






线程



这里所说的线程指程序执行过程中的一个线程实体。JVM 允许一个应用并发执行多个线程。Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系。当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。Java 线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。当线程结束时,会释放原生线程和 Java 线程的所有资源。



Hotspot JVM 后台运行的系统线程主要有下面几个:






JVM 内存区域







JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区域【JAVA 堆、方法区】、直接内存。



线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 HotspotVM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的生/死对应)。



线程共享区域随虚拟机的启动/关闭而创建/销毁。



直接内存并不是 JVM 运行时数据区的一部分, 但也会被频繁的使用: 在 JDK 1.4 引入的 NIO 提供了基于 Channel 与 Buffer 的 IO 方式, 它可以使用 Native 函数库直接分配堆外内存, 然后使用DirectByteBuffer 对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在 Java堆和 Native 堆中来回复制数据, 因此在一些场景中可以显著提高性能。





1、程序计数器(线程私有)



一块较小的内存空间, 是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。



正在执行 java 方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果还是Native 方法,则为空。



这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域。



2、虚拟机栈(线程私有)



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



栈帧( Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。





3、本地方法区(线程私有)



本地方法区和 Java Stack 作用类似, 区别是虚拟机栈为执行 Java 方法服务, 而本地方法栈则为Native 方法服务, 如果一个 VM 实现使用 C-linkage 模型来支持 Native 调用, 那么该栈将会是一个C 栈,但 HotSpot VM 直接就把本地方法栈和虚拟机栈合二为一。



4、堆(Heap-线程共享)-运行时数据区



是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。由于现代 VM 采用分代收集算法, 因此 Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。



5、方法区/永久代(线程共享)



即我们常说的永久代(Permanent Generation), 用于存储被 JVM 加载的类信息常量静态变量即时编译器编译后的代码等数据. HotSpot VM把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区, 这样 HotSpot 的垃圾收集器就可以像管理 Java 堆一样管理这部分内存,而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收类型的卸载, 因此收益一般很小)。



运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。 Java 虚拟机对Class 文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。




JVM 运行时内存





Java 堆从 GC 的角度还可以细分为:新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。






垃圾回收与算法








JAVA 四种引用类型





1、强引用



在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到 JVM 也不会回收。因此强引用是造成 Java 内存泄漏的主要原因之一。



2、软引用



软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。



3、弱引用



弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。



4、虚引用



虚引用需要 PhantomReference 类来实现,它不能单独使用,必须和引用队列联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态。




GC 分代收集算法 VS 分区收集算法







......




GC 垃圾收集器







......




JAVA IO/NIO







......





......



JVM 类加载机制



JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程。







......





如果你看完这些知识点发现自己都掌握了,薪资却没有18K,赶紧跳槽吧!



发布于: 2020 年 11 月 17 日阅读数: 72
用户头像

小Q

关注

还未添加个人签名 2020.06.30 加入

小Q 公众号:Java架构师联盟 作者多年从事一线互联网Java开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果能为您提供帮助,请给予支持(关注、点赞、分享)!

评论

发布
暂无评论
这套JVM核心知识你要全都会,月薪还不过18K可以直接跳槽了