更新时间:2023-02-03 11:49:09 来源:极悦 浏览922次
Jvm既可以操作系统平台相关信息又可以做到屏蔽作用,这就可以让Java程序只需要在Java虚拟机上实现在不同的平台上运行,所以我们在面试相关岗位的时候,Java Jvm方面的面试题会被频繁的问到,所以,正准备面试的同学,Java Jvm的面试题最好了解一些。
1.运行时数据区是什么
虚拟机在执行程序过程中,将虚拟机内部的内存区域划分成不同的数据区域。每个数据区都具有自己的生命周期和功能作用。
对于这一部分区域,我们可以根据线程的私有和线程共享来进行分类。
从线程独占角度 来看主要又 ;pc程序计数器 ,java虚拟机栈 ,本地方法栈
而线程共享来看则主要是的:堆和方法区。
2.堆的作用是什么
答题整体思路:点名堆内存的主要作用,之后深入至堆内存中年轻代、老年代的整体的布局情况。可以顺带提及minorgc和Full gc发生的时机。
如果时间充裕的话还可以扩展衍生至对象创建,对象分配的话题。一个小小的堆内存可以回答和扩展的点真的很多。
关于JVM中的堆内存,其主要功能就是用于存放java中的对象实例信息,同时在java虚拟机规范中也明确指出,对象信息和数组信息的创建应该带都分配在堆内存之中。
当我们知道了堆的主要作用后,接下来我们可以看看jvm的基本内存布局,整体来看在jvm的堆内存中,其主要主要存储区域分为年轻代和老年代。如果使用的版本是jdk8之前的版本则还有永久代的概念,而到了jdk8之后永久代则被元空间所取代。
对于我们的堆内存的年轻代来看,其内部又划分为两个survior区和一个eden区。这样设计的目的也主要是为了能更好的进行垃圾回收。我们都知道java中的对象通常朝生夕死,大部分对象的存活生命周期还是很短的,为了降低垃圾回收的频率,提升jvm的整体性能。所以设定两个survior区来进行垃圾的回收和处理。
如果细致来看,此时我们对于survior为什么设定两个?讨论这个问题的前提在于我们假定垃圾回收采用的算法是复制算法。
对于复制算法其主要过程如下:
1)Eden 区活着的对象 + From Survivor 存储的对象被复制到 To Survivor ;
2) 清空 Eden 和 From Survivor ;
3) 颠倒 From Survivor 和 To Survivor 的逻辑关系: From 变 To , To 变 From 。
说清楚复制算法之后,我们在开始讨论为什么设定surivor内存区域为两个。
这个问题我们来看0个,如果不设定survior区域,那么eden区满了之后就需要触发gc,此时幸存对象保存至老年代,这样老年代很快就会被填满,加剧了full gc所带来的性能损耗。
如果设定一个,我们都知道对于年轻代区而言,Eden区和suriovr区域的大小比为8:1,我们假设内存为9M则,eden占据8M,surivior占据1M,此时如果幸存区内容为0.5M则此时我们,此时surivior很快被填满,同时如果surivior作为对象分配内存的起点,此时又是会很快被填满。
在只有一个 Survivor 的情况下,无论 Eden 和 Survivor 的比例怎么设置,总体上看在新生代空间满一半的时候就会触发一次 Minor gc 。那有没有提升的空间呢?比如说永远在新生代空间满 80% 的时候才触发 Minor gc ?
此时就引出设计两个serviceor空间( From Survivor 和 To Survivor )的设计思路。此时把 Eden : From Survivor : To Survivor 空间大小设成 8 : 1 : 1 。
对象总是在 Eden 区出生, From Survivor 保存当前的幸存对象, To Survivor 为空。这样仅当eden区满之后才会触发minorgc,垃圾回收的频率被进一步降低,性能的影响也得以平衡。
3.方法区的作用是什么?
方法区用于存储被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
JDK8 之前使用永久代实现方法区,容易内存溢出,因为永久代有 上限,即使不设置也有默认大小。JDK7 把放在永久代的常量池、静态变量等移出,JDK8 中永久代完全废弃,改用在本地内存中实现的元空间代替,把 JDK 7 中永久代剩余内容(主要是类型信息)全部移到元空间。
虚拟机规范对方法区的约束宽松,除和堆一样不需要连续内存和可选择固定大小/可扩展外,还可以不实现垃圾回收。垃圾回收在方法区出现较少,主要目标针对常量池和类型卸载。如果方法区无法满足新的内存分配需求,将抛出 OutOfMemoryError
4.运行时常量池作用以及其同类文件中常量池的区别
运行时常量池是方法区的一部分,Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表,用于存放编译器生成的各种字面量与符号引用,这部分内容在类加载后存放到运行时常量池。一般除了保存 Class 文件中描述的符号引用外,还会把符号引用翻译的直接引用也存储在运行时常量池。
运行时常量池相对于 Class 文件常量池的一个重要特征是动态性,Java 不要求常量只有编译期才能产生,运行期间也可以将新的常量放入池中,这种特性利用较多的是 String 的 方法。
运行时常量池是方法区的一部分,受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError。
对于class 文件中的常量池,我们将 java 代码通过 javac 编译为 class 文件,接下来再运行 java 程序的时候就完全不需要 java 文件了,只需要 class 文件即可。而 class 文件是保存在本地磁盘上的文件,里面全是0101的字节码,或者说是字符串,那各个字符串之间如何产生联系呢?那就是通过常量池。
对于class常量池而言其在编译的时候每个class都有的,在编译阶段,主要存放的是常量的符号引用。
而运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中。两者产生时机并不相同,同时类常量池时静态的,而运行时常量池时动态的。
5.jvm中垃圾收集器有那些
一:Serial 收集器
Serial收集器是最基本的、发展历史最悠久的收集器。
特点:单线程、简单高效,对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程手机效率。收集器进行垃圾回收时,必须暂停其他所有的工作线程,直到它结束(Stop The World)。
二:ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本。
除了使用多线程外其余行为均和Serial收集器一模一样(参数控制、收集算法、Stop The World、对象分配规则、回收策略等)。
特点:多线程、ParNew收集器默认开启的收集线程数与CPU的数量相同,在CPU非常多的环境中,可以使用-XX:ParallelgcThreads参数来限制垃圾收集的线程数。
三:Serial Old 收集器
Serial Old是Serial收集器的老年代版本。
特点:同样是单线程收集器,但是面向老老年代的垃圾收集。采用标记-整理算法。
四:Parallel Old 收集器
概述:是Parallel Scavenge收集器的老年代版本。
特点:多线程,采用标记-整理算法。
五:CMS收集器
全称(Concurrent Mark Sweep)一种以获取最短回收停顿时间为目标的收集器。
特点:基于标记-清除算法实现。并发收集、低停顿。
应用场景:适用于注重服务的响应速度,希望系统停顿时间最短,给用户带来更好的体验等场景下。如web程序、b/s服务。
因为采用标记-清除算法所以会存在空间碎片的问题,导致大对象无法分配空间,不得不提前触发一次Full gc。
以上就是“大厂通用的Java jvm面试题”,你能回答上来吗?如果想要了解更多的相关内容,可以关注极悦Java官网。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习