最全JVM⾯试题
⽂章⽬录
1.说⼀下 JVM 的主要组成部分及组成部分的作⽤?
⽅法区和堆是所有线程共享的内存区域;⽽java栈、本地⽅法栈和程序员计数器是运⾏是线程私有的内存区域,运⾏时数据区域就是我们常说的JVM的内存。
类加载⼦系统:根据给定的全限定名类名(如:java.lang.Object)来装载class⽂件到运⾏时数据区中的⽅法区中。
Java堆是Java虚拟机所管理的内存中最⼤的⼀块,也是垃圾回收的主要区域。Java堆是被所有线程共享的⼀块内存区域,在虚拟机启动时创建。此内存区域的唯⼀⽬的就是存放对象实例,⼏乎所有的对象实例都在这⾥分配内存。
⽅法区与Java堆⼀样,是各个线程共享的内存区域,它⽤于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
程序计数器是⼀块较⼩的内存空间,它的作⽤可以看做是当前线程所执⾏的字节码的⾏号指⽰器,⽤来指⽰执⾏引擎下⼀条执⾏指令的地址。
Java虚拟机栈也是线程私有的,它的⽣命周期与线程相同。虚拟机栈描述的是Java⽅法执⾏的内存模型:每个⽅法被执⾏的时候都会同时创建⼀个栈帧(Stack Frame)⽤于存储局部变量表、操作数栈、动态链接、返回⽅法地址等信息。每⼀个⽅法被调⽤直⾄执⾏完成的过程,就对应着⼀个栈帧在虚拟机栈中从⼊栈到出栈的过程。
本地⽅法栈(Native Method Stacks),本地⽅法栈(Native Method Stacks)与虚拟机栈所发挥的作⽤是⾮常相似的,其区别不过是虚拟机栈为虚拟机执⾏Java⽅法(也就是字节码)服务,⽽本地⽅法栈则是为虚拟机使⽤到的Native⽅法服务。
执⾏引擎:根据程序计数器中存储的指令地址执⾏classes中的指令。
本地接⼝:与本地⽅法库交互,是其它编程语⾔交互的接⼝。
2.说⼀下 JVM 的作⽤?
⾸先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运⾏时数据区(Runtime data area)的⽅法区内,⽽字节码⽂件只是 JVM 的⼀套指令集规范,并不能直接交给底层操作系统去执⾏,因此需要特定的命令解析器执⾏引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执⾏,⽽这个过程中需要调⽤其他语⾔的本地库接⼝(Native Interface)来实现整个程序的功能。
3.深拷贝和浅拷贝
浅拷贝:只是增加了⼀个指针指向已存在的内存地址,
深拷贝:是增加了⼀个指针并且申请了⼀个新的内存,使这个增加的指针指向这个新的内存,
使⽤深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同⼀个内存的错误。
浅复制:仅仅是指向被复制的内存地址,如果原地址发⽣改变,那么浅复制出来的对象也会相应的改变。
深复制:在计算机中开辟⼀块新的内存地址⽤于存放复制的对象。
4.说⼀下堆栈的区别?
物理地址
堆的物理地址分配对对象是不连续的。因此性能慢些。在GC的时候也要考虑到不连续的分配,所以有各种算法。⽐如,标记-消除,复制,标记-压缩,分代(即新⽣代使⽤复制算法,⽼年代使⽤标记——压缩)
栈使⽤的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。
内存分别
堆因为是不连续的,所以分配的内存是在运⾏期确认的,因此⼤⼩不固定。⼀般堆⼤⼩远远⼤于栈。
栈是连续的,所以分配的内存⼤⼩要在编译期就确认,⼤⼩是固定的。
存放的内容
堆存放的是对象的实例和数组。因此该区更关注的是数据的存储
栈存放:局部变量,操作数栈,返回结果。该区更关注的是程序⽅法的执⾏。
PS:
java核心技术有哪些静态变量放在⽅法区
静态的对象还是放在堆。
程序的可见度
堆对于整个应⽤程序都是共享、可见的。
栈只对于线程是可见的。所以也是线程私有。他的⽣命周期和线程相同。
5.队列和栈是什么?有什么区别?
队列和栈都是被⽤来预存储数据的。
操作的名称不同。队列的插⼊称为⼊队,队列的删除称为出队。栈的插⼊称为进栈,栈的删除称为出栈。
可操作的⽅式不同。队列是在队尾⼊队,队头出队,即两边都可操作。⽽栈的进栈和出栈都是在栈顶进⾏的,⽆法对栈底直接进⾏操作。
操作的⽅法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进⾏的。新来的成员总是加⼊队尾(不能从中间插⼊),每次离开的成员总是队列头上(不允许中途离队)。⽽栈为后进先出(LIFO),即每次删除(出栈)的总是当前栈中最新的元素,即最后插⼊(进栈)的元素,⽽最先插⼊的被放在栈的底部,要到最后才能删除。
6.对象的创建⽅式和步骤
7.创建对象时为对象分配内存
8.创建对象时处理并发安全问题
9.创建对象时对象的访问定位
句柄访问
直接指针
10.Java内存泄漏
内存泄漏是指不再被使⽤的对象或者变量⼀直被占据在内存中。
严格来说,只有对象不会再被程序⽤到了,但是GC⼜不能回收他们的情况,才叫内存泄漏。
理论上来说,Java是有GC垃圾回收机制的,也就是说,不再被使⽤的对象,会被GC⾃动回收掉,⾃动从内存中清除。
但是,即使这样,Java也还是存在着内存泄漏的情况,java导致内存泄露的原因很明确:长⽣命周期的对象持有短⽣命周期对象的引⽤就很可能发⽣内存泄露,尽管短⽣命周期对象已经不再需要,但是因为长⽣命周期对象持有它的引⽤⽽导致不能被回收,这就是java中内存泄露的发⽣场景。
11.简述Java垃圾回收机制
在java中,程序员是不需要显⽰的去释放⼀个对象的内存的,⽽是由虚拟机⾃⾏执⾏。在JVM中,有⼀个垃圾回收线程,它是低优先级的,在正常情况下是不会执⾏的,只有在虚拟机空闲或者当前堆内存不⾜时,才会触发执⾏,扫⾯那些没有被任何引⽤的对象,并将它们添加到要回收的集合中,进⾏回收。
12.Java 中都有哪些引⽤类型?
强引⽤:发⽣ gc 的时候不会被回收。
软引⽤:有⽤但不是必须的对象,在发⽣内存溢出之前会被回收。
弱引⽤:有⽤但不是必须的对象,在下⼀次GC时会被回收。
虚引⽤(幽灵引⽤/幻影引⽤):⽆法通过虚引⽤获得对象,⽤PhantomReference 实现虚引⽤,虚引⽤的⽤途是在 gc 时返回⼀个通知。
13.如何判断对象是否可以被回收
引⽤计数器法:为每个对象创建⼀个引⽤计数,有对象引⽤时计数器 +1,引⽤被释放时计数 -1,当计数器为 0 时就可以被回收。它的缺点是增加了时间和空间消耗以及不能解决循环引⽤的问题;
可达性分析算法:从 GC Roots 开始向下搜索,搜索所⾛过的路径称为引⽤链。当⼀个对象到 GC Roots 没有任何引⽤链相连时,则证明此对象是可以被回收的。
14.说⼀下 JVM 有哪些垃圾回收算法?
标记-清除算法:标记有⽤对象,然后进⾏清除回收。缺点:效率不⾼,⽆法清除垃圾碎⽚。
复制算法:按照容量划分⼆个⼤⼩相等的内存区域,当⼀块⽤完的时候将活着的对象复制到另⼀块上,然后再把已使⽤的内存空间⼀次清理掉。缺点:内存使⽤率不⾼,只有原来的⼀半,消耗内存。
标记-整理算法:标记⽆⽤对象,让所有存活的对象都向⼀端移动,然后直接清除掉端边界以外的内存。
分代算法:根据对象存活周期的不同将内存划分为⼏块,⼀般是新⽣代和⽼年代,新⽣代基本采⽤复制算法,⽼年代采⽤标记整理算法。
15.说⼀下 JVM 有哪些垃圾回收器?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论