培养顶尖技术思维
概述:总结知识点
jvm的知识点总结了六个大方向:内存模型、类加载机制和GC垃圾回收。性能调整部分侧重于实际应用,侧重于实践能力。编译器优化和执行模式侧重于理论基础,主要掌握知识点。
各部分的内容如下:
1>内存模型部分:程序计数器、方法区、堆栈、堆栈、本地方法堆栈的作用,保存哪些数据;
2>类加载部分:双亲委派的加载机制和常用加载器分别加载哪种类型;
3>GC部分:分代回收的理念和依据,以及实现不同垃圾回收算法的理念和合适的场景;
4>性能调优部分:常用的jvm优化参数的作用,参数调优的依据,了解常用的jvm分析工具可以分析哪些问题,以及使用方法;
5>执行模式部分:了解Java7提供的分层编译技术,解释、编译和混合模式的优缺点。需要知道JIT即时编译技术和OSR,即堆栈替换,C1、C2编译器针对的场景,其中C2针对server模式,优化更加激进。在新技术方面,我们可以了解java10提供的graal编译器。
6>编译优化部分:编译过程、AST抽象语法树、编译期优化和运行期优化。编译优化的常用技术包括公共子表达式消除、方法内联、逃逸分析、堆栈分布、同步消除等。只有理解了这些,我们才能写出对编译器友好的代码。
jvm的内容相对集中,但对知识深度的掌握要求较高。建议在面试前加强重点。
一、jvm内存相关考点
1.详解-jvm内存模型
jvm内存模型主要是指运行时的数据区,包括五个部分。
栈,又称方法栈,是线程私有的。在执行每种方法时,线程将同时创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息。调用方法时,进入栈,返回栈。
本地方法栈类似于栈,也用于保存线程执行方法的信息。不同的是,java方法使用栈,native方法使用本地方法栈。
程序计数器保存当前线程执行的字节码位置,每个线程工作时都有一个独立的计数器。当程序计数器执行java方法和native方法时,程序计数器是空的。
栈、本地方法栈、程序计数器三部分是线程独有的。
堆是jvm管理中最大的内存部分。堆被所有线程共享,目的是存储对象的例子,几乎所有的例子都分布在这里。当堆内存没有可用的空间时,OOM异常就会被抛出。jvm根据对象的生存周期对堆内存进行分代管理,垃圾回收器对对象进行回收管理。
方法区也是每个线程共享的内存区,也被称为非堆叠区。用于存储虚拟机加载的信息、常量、静态变量、即时编译器编译的代码等数据,
jdk1.7中的永久代和1.8中的metaspace都是方法区的一种实现。
面试回答这个知识点的相关问题时,要回答两个关键点:一是各部分的功能,二是线程共享和独占性。
2.详解-jmm内存的可见性
jmm是java内存模型,这与刚才提到的jvm内存模型不同。jmm的主要目标是定义程序中变量的访问规则。如图所示,所有共享变量都存储在主内存中共享。每个线程都有自己的工作内存。主内存中的变量副本保存在工作内存中。线程读写变量必须在其自身中进行 在工作内存中进行,而不是直接读写主内存中的变量。
当多线程进行数据交互时,例如,在线程a给出共享变量赋值后,线程b将读取该值。a修改变量后,将变量修改为自己的工作区域内存。b是看不见的。只有从a的工作区域写回主内存,b然后从主内存读取到自己的工作区域,才能进一步操作。由于指令重新排序的存在,写读顺序可能会被打乱。
因此,jmm需要提供原子性、可见性和有序性的保证。
3、详细说明-jmm保证
主要介绍jmm如何保证原子性、可见性和有序性。
jmm保证除long和double以外的基本数据类型的读写操作是原子性的。此外,关键字synchronized还可以提供原子性保证。synchronized的原子性是通过java的两个高级字节码指令monitorenter和monitorexit来保证的。
jmm可见性的保证,一个是通过synchronized,另一个是volatile。volatile强制变量的赋值将同时刷新回主内存,强制变量的读取将从主内存重新加载,以确保不同线程总能看到变量的最新值。
jmm对有序性的保证主要是通过volatile和一系列happens-before原则。volatile的另一个功能是防止指令重新排序,从而保证变量读写的有序性。
happens-before原则包括一系列规则,如
- 程序顺序原则,即语义串行必须在一个线程中得到保证;
- 锁定规则,即同一锁的解锁必须在再次加锁前发生;
- 还包括happens-before原则的传递、线程启动、中断、终止规则等。
二、类加载机制相关考点
1.详细解释类加载机制
类加载是指将编译好的class文件中的字节码读入内存,放入方法区,创建相应的class对象。
加载分为加载、链接和初始化,包括验证、准备和分析三个步骤。看到图中上半部分的深绿色,我们逐一分析:
加载是从文件到内存的过程。通过类别的完全限定名找到此类字节码文件,并使用字节码文件创建Class对象
验证是对类别文件内容的验证。目的是确保class文件符合当前虚拟机的要求,不会危及虚拟机本身的安全。主要包括四种类型:文件格式验证、元数据验证、字节码验证、符号引用验证。
准备阶段是内存分配。对于类变量,即由static修改的类变量来分配内存并设置初始值。这里需要注意的是,初始值是0或null,而不是代码中设置的具体值。代码中设置的值在初始化阶段完成。此外,这里不包括用final修改的静态变量,因为final将在编译过程中分配。
分析主要是分析字段、接口和方法。主要是用直接引用代替常量池中的符号的过程。直接引用是直接指向目标的指针、相对偏移量等。
最后是初始化:主要完成静态块执行和静态变量的赋值。这是类加载的最后阶段。如果加载的父亲没有初始化,则首先对父亲进行初始化。
只有当主动使用类别时,才会初始化。初始化的触发条件包括创建类别的例子、访问类别的静态方法或静态变量,Class.forName()反射类或子类初始化的时候。
类的生命周期是GC从类加载到类实例的创建和使用,再到类对象不再使用时可以卸载和回收。这里需要注意的是,Java虚拟机加载的三种类型的加载器不会在虚拟机的整个生命周期中卸载,只有用户自定义的类别加载器加载的类别才能卸载。
2.详解类加载器
java有三种类型的加载器:botstrap启动加载器、扩展加载器和应用加载器,也称为系统加载器。图右侧的橙色文本表示各种加载器对应的加载目录。启动加载器加载java home中lib目录下的类别,扩展加载器负责加载ext目录下的类别,应用加载器加载claspath指定目录下的类别。
此外,还可以定制自定义加载器。
java的类加载采用父亲分配模式,即当一个类加载器加载时,首先委托其父亲加载器执行此请求。如果父亲加载器仍然有父亲加载器,继续委托它,直到顶部的启动加载器,如图中的蓝色向上箭头。如果父亲加载器能够完成类加载,则成功返回。如果父亲加载器不能完成加载,子加载器将尝试自己加载。
这种双亲分配模式的好处是可以避免重复加载类别,也可以避免篡改java的核心API。
三、梳理其他知识
1.详细说明分代回收
正如前面提到的,java的堆内存被分代管理,主要是为了方便垃圾回收。基于两个事实,首先,大多数对象很快就不再使用,其次,有些不会立即无用,但不会持续很长时间。
虚拟机分为年轻、老年和永久。
1>年轻一代:主要用于存储新创建的对象。年轻一代分为eden区和两个survivor区。大多数对象都是在eden区生成的。当eden区满时,仍然存活的对象将在两个survivor区交替保存,达到一定数量的对象将升级到老年。
2>老年人:用于存放从年轻时晋升而来的存活时间较长的对象。
3>永久代:主要保存类信息等内容。这里的永久代是指对象的划分,而不是1.7的permgen,或者1.8后的metaspace。
jvm根据年轻人和老年人的特点,提供了不同的垃圾回收算法。垃圾回收算法可分为引用计数法、复制法和标记清除法。
引用计数法是通过引用对象的次数来确定对象是否被使用,缺点是不能解决循环引用的问题。
复制算法需要两个相同大小的内存空间:from和to。当对象分配时,只在from块中进行。回收时,将生存对象复制到to块中,清空from块,然后交换两个分工,即from块作为to块,to块作为from块。缺点是内存利用率低。
标记清除算法分为两个阶段:标记对象和清除未使用的对象。标记清除算法的缺点是会产生内存碎片。
在jvm中提供的年轻一代回收算法Serial、ParNew、Parallel Scavenge是复制算法,而CMS、G1、zgc属于标记清除算法。
本文没有扩展这些算法,具体可见32个Java面试必考点
总结:面试调查点及加分项目
1.与jvm相关的面试调查点
首先,需要jvm内存模型和java内存模型;
其次,要了解类别的加载过程,了解父母的分配机制;
第三,要了解内存的可见性和java内存模型对原子性、可见性和有序性的保证机制;
第四,了解常用GC算法的特点、执行过程和适用场景。例如,G1适用于需要最大延迟的场合,ZGC适用于64系统的大内存服务;
第五,了解常用的jvm参数,了解对不同参数的调整会有什么影响,适用于什么样的场景。例如,垃圾回收的并发数、偏向锁设置等
2.相关加分项
如果你想让面试官给你留下更好的印象,请注意这些奖励:
首先,如果你对编译器优化有深入的了解,面试官会觉得你对技术的深度有更多的追求。例如,知道如何合理地使用堆栈来减少GC压力,以及如何编写适合内部优化的代码。
其次,如果你有在线实际问题的调查经验或想法,那就更好了。面试官喜欢动手能力强的学生。例如,经常在线解决fulll问题 GC问题,内存泄漏问题等。
第三,如果有针对特定场景的jvm优化实践或优化思路,也会产生意想不到的效果。例如,对于高并发低延迟的场景,如何调整gc参数,尽量减少gc停顿时间,如何尽可能提高队列处理器的吞吐率;
第四,如果你了解jvm的最新技术趋势,也会给面试官留下深刻的印象。比如了解zgc的高效实现原理和gralvm的特点。
简而言之,掌握上述具体情况JVM只有考点才能在面试中自由回应。希望看完这篇文章,能在金三银四的招聘季做好准备,得到自己喜欢的offer。
摘自以上内容
32个Java面试必考点
第03讲:简单的JVM