每日一题挑战年薪50万JVM高频面试题(阿里秋招篇)
基础1。JDK、JRE、JVM的关系是什么?什么是JVM?英文名称(JavaVirtualMachine),就是JAVA虛拟机,它只识别。class类型文件,它能够将class文件中的字节码指令进行识别并调用操作系统向上的API完成动作。什么是JRE?英文名称(JavaRuntimeEnvironment),Java运行时环境。它主要包含两个部分:JVM的标准实现和Java的一些基本类库。相对于JVM来说,JRE多出来一部分Java类库。什么是JDK?英文名称(JavaDevelopmentKit),Java开发工具包。JDK是整个Java开发的核心,它集成了JRE和一些好用的小工具。例如:javac。exe、java。exe、jar。exe等。这三者的关系:一层层的嵌套关系。JDKJREJVM。2。JVM的内存模型以及分区情況和作用
如下图所示:
黄色部分为线程共有,蓝色部分为线程私有。方法区用于储存虚拟机加载的类信息,常量,静态变量等数据。堆存放对象实例,所有的对象和数组都要在堆上分配,是JVM所管理的内存中最大的一块区域。栈Java方法执行的内存模型:存储局部变量表,操作数栈,动态链接,方法出口等信息,生命周期与线程相同。本地方法栈作用与虚拟机栈类似。不同点本地方法栈为native方法执行服务虚拟机栈为虚拟机执行的Java方法服务。程序计数器当前线程所执行的行号指示器,是JVM内存区域最小的一块区域,执行字节码工作时就是利用程序计数器来选取下一条需要执行的字节码指令。3。JVM对象创建步骤流程是什么?
整体流程如下图所示:
第1步:虚拟机遇到一个new指令,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用的类是否已经被加载解析初始化。第2步:如果类已经被加载那么进行第3步;如果没有进行加载,那么就需要先进行类的加载。第3步:类加载检查通过之后,接下来进行新生对象的内存分配。第4步:对象生成需要的内存大小在类加载完成后便可完全确定,为对象分配空间等同于把一块确定大小的内存从Java堆中划分出来。第5步:内存大小的划分分为两种情况:第一种情况:JVM的内存是规整的,所有的使用的内存都放到一边,空闲的内存在另外一边,中间放一个指针作为分界点的指示器。那么这时候分配内存就比较简单,只要讲指针向空闲空间那边挪动一段与对象大小相同的距离。这种就是指针碰撞。第二种情況:JVM的内存不是规整的,也就是说已使用的内存与未使用的内存相互交错。这时候就没办法利用指针碰撞了。这时候我们就需要维护一张表,用于记录那些内存可用,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新到记录表上。第6步:空间申请完成之后,JVM需要将内存的空间都初始化为0值。如果使用TLAB,就可以在TLAB分配的时候就可以进行该工作。第7步:JVM对对象进行必要的设置。例如,这个对象是哪个类的实例、对象的哈希码、GC年代等信息。第8步:完成了上面的步骤之后从JVM来看一个对象基本上完成了,但从Java程序代码绝对来看,对象创建才刚刚开始,需要执行init方法,按照程序中设定的初始化操作初始化,这时候一个真正的程序对象生成了。4。垃圾回收算法有几种类型?他们对应的优缺点又是什么?常见的垃圾回收算法有:标记清除算法复制算法标记整理算法分代收集算法标记清除算法标记清除算法包括两个阶段:标记和清除。标记阶段:确定所有要回收的对象,并做标记。清除阶段:将标记阶段确定不可用的对象清除。缺点:1。标记和清除的效率都不高。2。会产生大量的碎片,而导致频繁的回收。复制算法内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉。缺点:1。需要浪费额外的内存作为复制区。2。当存活率较高时,复制算法效率会下降。标记整理算法标记整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存。缺点:算法复杂度大,执行步骤较多分代收集算法目前大部分JVM的垃圾收集器采用的算法。根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为新生代(YoungGeneration)和老年代(TenuredGeneration),永久代(PermanetGeneration)。老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。Young:存放新创建的对象,对象生命周期非常短,几乎用完可以立即回收,也叫Eden区。Tenured:Young区多次回收后存活下来的对象将被移到Tenured区,也叫old区。Perm:永久带,主要存加载的类信息,生命周期长,几乎不会被回收。缺点:算法复杂度大,执行步骤较多。
5。简单介绍一下什么是类加载机制?Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等。虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。6。类的加载过程是什么?简单描述一下每个步骤
类加载的过程包括了:五个阶段:加载验证准备解析初始化第一步:加载
加载是类加载过程的第一个阶段,虚拟机在这一阶段需要完成以下三件事情:通过类的全限定名来获取其定义的二进制字节流将字节流所代表的静态存储结构转化为方法区的运行时数据结构在Java堆中生成一个代表这个类的java。lang。Class对象,作为对方法区中这些数据的访问入口第二步:验证
确保被加载的类的正确性。
这一阶段是确保Class文件的字节流中包含的信息符合当前虚拟机的规范,并且不会损害虚拟机自身的安全。
包含了四个验证动作:文件格式验证,元数据验证,字节码验证,符号引用验证。第三步:准备
为类的静态变量分配内存,并将其初始化为默认值。
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。第四步:解析
把类中的符号引用转换为直接引用。
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。第五步:初始化
类变量进行初始化。
为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。7。JVM预定义的类加载器有哪几种?分别什么作用?启动(Bootstrap)类加载器标准扩展(Extension)类加载器应用程序类加载器(Application)启动(Bootstrap)类加载器引导类装入器是用本地代码实现的类装入器,它负责将JavaRuntimeHomelib下面的类库加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用。标准扩展(Extension)类加载器扩展类加载器负责将JavaRuntimeHomelibext或者由系统变量java。ext。dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。应用程序类加载器(Application)应用程序类加载器(ApplicationClassLoader):负责加载用户路径(classpath)上的类库。8。什么是双亲委派模式?有什么作用?基本定义双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器没有找到所需的类时,子加载器才会尝试去加载该类。双亲委派机制:1。当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。2。当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。3。如果BootStrapClassLoader加载失败,会使用ExtClassLoader来尝试加载。4。若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。
如下图所示:
双亲委派作用:通过带有优先级的层级关可以避免类的重复加载。保证Java程序安全稳定运行,Java核心API定义类型不会被随意替换。8。介绍一下JVM中垃圾收集器有哪些?他们特点分别是什么?新生代垃圾收集器Serial收集器特点:Serial收集器只能使用一条线程进行垃圾收集工作,并且在进行垃圾收集的时候,所有的工作线程都需要停止工作,等待垃圾收集线程完成以后,其他线程才可以继续工作。使用算法:复制算法ParNew收集器特点:ParNew垃圾收集器是Serial收集器的多线程版本。为了利用CPU多核多线程的优势,ParNew收集器可以运行多个收集线程来进行垃圾收集工作。这样可以提高垃圾收集过程的效率。使用算法:复制算法ParallelScavenge收集器特点:ParallelScavenge收集器是一款多线程的垃圾收集器,但是它又和ParNew有很大的不同点。ParallelScavenge收集器和其他收集器的关注点不同。其他收集器,比如ParNew和CMS这些收集器,它们主要关注的是如何缩短垃圾收集的时间。而ParallelScavenge收集器关注的是如何控制系统运行的吞吐量。这里说的吞吐量,指的是CPU用于运行应用程序的时间和CPU总时间的占比,吞吐量代码运行时间(代码运行时间垃圾收集时间)。如果虚拟机运行的总的CPU时间是100分钟,而用于执行垃圾收集的时间为1分钟,那么吞吐量就是99。使用算法:复制算法老年代垃圾收集器SerialOld收集器特点:SerialOld收集器是Serial收集器的老年代版本。这款收集器主要用于客户端应用程序中作为老年代的垃圾收集器,也可以作为服务端应用程序的垃圾收集器。使用算法:标记整理ParallelOld收集器特点:ParallelOld收集器是ParallelScavenge收集器的老年代版本这个收集器是在JDK1。6版本中出现的,所以在JDK1。6之前,新生代的ParallelScavenge只能和SerialOld这款单线程的老年代收集器配合使用。ParallelOld垃圾收集器和ParallelScavenge收集器一样,也是一款关注吞吐量的垃圾收集器,和ParallelScavenge收集器一起配合,可以实现对Java堆内存的吞吐量优先的垃圾收集策略。使用算法:标记整理CMS收集器特点:CMS收集器是目前老年代收集器中比较优秀的垃圾收集器。CMS是ConcurrentMarkSweep,从名字可以看出,这是一款使用标记清除算法的并发收集器。CMS垃圾收集器是一款以获取最短停顿时间为目标的收集器。
如下图所示:
从图中可以看出,CMS收集器的工作过程可以分为4个阶段:初始标记(CMSinitialmark)阶段并发标记(CMSconcurrentmark)阶段重新标记(CMSremark)阶段并发清除((CMSconcurrentsweep)阶段
使用算法:复制标记清除G1垃圾收集器特点:主要步骤:初始标记,并发标记,重新标记,复制清除。使用算法:复制标记整理9。什么是Class文件?Class文件主要的信息结构有哪些?Class文件是一组以8位字节为基础单位的二进制流。各个数据项严格按顺序排列。Class文件格式采用一种类似于C语言结构体的伪结构来存储数据。这样的伪结构仅仅有两种数据类型:无符号数和表。无符号数:是基本数据类型。以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数,能够用来描写叙述数字、索引引用、数量值或者依照UTF8编码构成的字符串值。表:由多个无符号数或者其它表作为数据项构成的复合数据类型。全部表都习惯性地以info结尾。10。对象对象已死是什么概念?对象不可能再被任何途径使用,称为对象已死。判断对象已死的方法有:引用计数法与可达性分析算法。迸阶11。Java语言怎么实现跨平台的?我们编写的Java源码,编译后会生成一种。class文件,称为字节码文件。字节码不能直接运行,必须通过JVM翻译成机器码才能运行,JVM是一个桥梁,是一个中间件,是实现跨平台的关键。Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。12。JVM数据运行区,哪些会造成OOM的情况?除了数据运行区,其他区域均有可能造成OOM的情况。堆溢出:java。lang。OutofMemoryError:Javaheapspace栈溢出:java。lang。StackoverflowError永久代溢出(内存溢出):java。lang。outofMemoryError:PermGenspace13。详细介绍一下对象在分带内存区域的分配过程?1。JVM会试图为相关Java对象在Eden中初始化一块内存区域。2。当Eden空间足够时,内存申请结束;否则到下一步。3。JVM试图释放在Eden中所有不活跃的对象(这厲于1或更高级的垃圾回收)。释放后若Eden空问仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区。4。Survivor区被用区作为Eden及old的中间交换区域,当old区空间足够时,Survivor区的对象会被移到old区,否则会被保留在Survivor区。5。当old区空间不够时,JVM会在old区进行完全的垃圾收集。6。完全垃圾收集后,若survivor及old区仍然无法存放从Eden复制过区的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现outofmemory错误。14。G1与CMS两个垃圾收集器的对比细节方面不同G1在压缩空间方面有优势。G1通过将内存空问分成区域(Region)的方式避免内存碎片问题,Eden,Survivor,old区不再固定、在内存使用效率上区说更灵活。G1可以通过设置预期停顿时间(PauseTime)区控制垃圾收集时间避免应用雪崩现象。G1在回收内存后会马上同时做合并空闲内存的工作、而CMS默认是在STW(stoptheworld)的时候做G1会在YoungGC中使用、而CMS只能在o区使用。整体内容不同吞吐量优先:G1响应优先:CMSCMS的缺点是对cpu的要求比较高。G1是将内存化成了多块,所有对内段的大小有很大的要求。CMS是清除,所以会存在很多的内存碎片。G1是整理,所以碎片空间较小。15。线上常用的JVM参数有哪些?数据区设置Xms:初始堆大小Xmx:最大堆大小Xss:Java每个线程的Stack大小XX:NewSizen:设置年轻代大小。XX:NewRation:设置年轻代和年老代的比代。如:为3,表示年轻代与年老代比代为1:3,年轻代占整个年轻代年老代和的14。XX:SurvivorRation:年轻代中Eden区与两个Survivor区的比代。注意Survivor区有两个。如:3,表示Eden:Survivor3:2,一个survivor区占整个年轻代的15。XX:MaxPermSizen:设置持久代大小。收集器设置XX:UseSesialGC:设置串行收集器XX:UsePasallelGC:设置并行收集器XX:UsePasalledlOldGC:设置并行年老代收集器XX:UseConcMaskSweepGC:设置并发收集器GC日志打印设置XX:PsintGC:打印GC的简要信息XX:PsintGCDetails:打印GC详细信息XX:PsintGCTimeStamps:输出GC的时间戳16。对象什么时候进入老年代?对象优先在Eden区分配内存当对象首次创建时,会放在新生代的eden区,若没有GC的介入,会一直在eden区,GC后,是可能进入susvivos区或者年老代大对象直接进入老年代所谓的大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组,大对象对虛拟机的内存分配就是坏消息,尤其是一些朝生夕灭的短命大对象,写程序时应避免。长期存活的对象进入老年代所谓的大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组,大对象对虛拟机的内存分配就是坏消息,尤其是一些朝生夕灭的短命大对象,写程序时应避免。17。什么是内存溢出,内存泄露?他们的区别是什么?内存溢出outofmemory,是指程序在申请内存时,没有足够的内存空间供其使用,出现outofmemosy;内存泄露memoryleak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆略后果很严重,无论多少内存,迟早会被占光。内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。18。引起类加载操作的操为有哪些?1。遇到new、getstatic、putstatic或invokestatic这四条字节码指令。2。反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。3。子类初始化的时候,如果其父类还没初始化,则需先触发其父类的初始化。4。虚拟机执行主类的时候(有main(stringllargs))5。JDK1。7动态语言支持。19。介绍一下JVM提供的常用工貝jps:用来显示本地的Java进程,可以查看本地运行着几个Java程序,并显示他们的进程号
命令格式:ipsjinfo:运行环境参数:JavaSystem属性和JVM命令行参数,Javaclasspath等信息
命令格式:info进程pidjstat:监视虛拟机各种运行状态信息的命令行工具
命令格式:jstatgc12325020jstack:可以观察到JVM中当前所有线程的运行情况和线程当前状态。
命令格式:istack进程pidjmap:观察运行中的JVM物理内存的占用情况(如:产生哪些对象,及其数量)
命令格式:jmap〔loption〕pid20。FullGC、MajorGC、MinorGC之间区别?MinorGC:从新生代空间(包括Eden和Survivor区域)回收内存被称为MinorGC。MajorGC:清理Tenured区,用于回收老年代,出现MajorGC通现会出现至少一次MinorGC。FullGC:FullGC是针对整个新生代、老年代、元空间(metaspace,java8以上版本取代permgen)的全局范围的GC。21。什么时候触发FullGC?调用System。gc时,系统建议执行FullGC,但是不必然执行。老年代空间不足。方法区空间不足。超过MinorGC后进入老年代的平均大小大于老年代的可用内存。由Eden区、survivorspacel(FromSpace)区向survivorspace2(ToSpace)区复制时,对象大小大于ToSpace可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。22。什么情况下会出现栈溢出方法创建了个很大的对象,如List,Array。是否产生了循环调用、死循环。是否引用了较大的全局变量。23。说一下强引用、软引用、弱引用、虛引用以及他们之间和GC的关系强引用:new出的对象之类的引用,只要强引用还在,永远不会回收。软引用:引用但非必须的对象,内存溢出异常之前,回收。弱引用:非必须的对象,对象能生存到下一次垃圾收集发生之前。虚引用:对生存时间无影响,在垃圾回收时得到通知。24。Eden和Survivor的比例分配是什么情况?为什么?默认比例8:1。大部分对象都是朝生夕死。复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。实战25。CPU资源占用过高top查看当前CPU情况,找到占用CPU过高的进程PID123。topHp123找出两个CPU占用较高的线程,记录下来PID2345,3456转换为十六进制。jstackl123temp。txt打印出当前进程的线程栈。查找到对应于第二步的两个线程运行栈,分析代码。26。00M异常排查使用top指令查询服务器系统状态。psauxgrepjava找出当前Java进程的PID。jmaphisto:dvepid可用统计存活对象的分布情况,从高到低查看占据内存最多的对象。jmapdump:formatb,fice文件名〔pid〕利用Jmapdump。使用性能分析工具对上一步dump出来的文件进行分析,工具有MAT等。
最后
如果觉得对你有帮助,可以转发此文保存收藏下来,收藏学会!