面试是不是问到jvm虚拟机的时候经常被怼,但是自己想看看java虚拟机又看不下去?下面是我自己总结的jvm的一下面试准备,以后你就可以跟面试官说,请你不要在问我jvm了!
一:首先什么事jvm?
jvm是java Virtual Machine的缩写,他是一种设计规范,是一个虚拟的计算机,通过在实际的计算机上模拟各种计算机功能的实现,有一套字节码指令,一组寄存器,一个栈,一个垃圾回收器,和一个存储方方法区,jvm屏蔽了与具体操作系统平台相关的信息,使java程序只需要生成字节码就可以在多个不同打的平台上运行,jvm在执行字节码时,还是要把字节码解释成具体平台上的机器指令
二:简述运行时数据区(其实也就是jvm的内存结构)包括那几个部分?
程序计数器
java栈
本地方法栈
方法区
堆
三:简述下每个部分主要的作用?
java堆内存:是用来存储对象本身的以及数组,记住所有通过new出来的对象都在堆中,这部分空间也是java垃圾回收器管理的主要区域,另外堆是被所有线程共享的,所以线程不安全在jvm中只有一个堆
jvm栈:是线程私有的(线程安全的),每个线程创建时都会创建jvm栈,jvm栈中存放的为当前线程中局部基本类型变量(java中定义的八种基本类型),部分的结果返回及stack Frame,非基本的对象在jvm栈上仅存放一个向上的地址
方法区:存放了所有加载类的信息(名称,修饰符),类中的静态变量,类中的Field信息,类中的方法信息,当开发人员在程序中同通过class对象中的getName isInterFace 等方法来获取信息时,这些数据都来自于方法区,同时方法区的也是数据共享的,在一定条件下会被GC 垃圾回收,当方法区的需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误
线程私有就是线程安全:
程序计数器
虚拟机栈
本地方法区
线程共享的:
堆
方法区
直接内存
四:java对象的出创建?
五:分配内存会出现什么问题?
分配内存都是在堆中进行的,堆是线程共享的,所以会产生线程安全问题,jvm虚拟机采用两种
方式,来保证线程安全问题:
1.CVS+失败重试,CVS是乐观锁的一种实现方式,乐观锁顾名思义就是乐观,想着没有其他线程来
修改,则不进行加锁,如果有其他线程则会冲突,失败就重试,直到成功为止,虚拟机采用CVS配上失败重试
方式来保证原子性
2.TLAB:为每一个线程预先在Eden区分配一块内训,jvm在给线程中的对象分配内存时,首先在TLAB分配
当对象大于TLAB中剩余内存或TLAB的内存用尽时,再采用CAS进行内存分配
六:什么情况下会栈内存溢出,堆内存溢出?
循环调用死循环
创建一个很大的对象,如list和array 较大的全局变量
七:jvm体系结构,以及说一些类加载器?
jvm体系机构由类加载器,执行引擎运行时数据区域组成
类加载器主要分为:
引导类加载器BootStrap ClassLoader,扩展类加载器Extension ClassLoader
系统类加载器APP ClassLoader和自定义加载器Custom ClassLoader
八:jvm 怎么确定那些对象应该进行回收?
对象是否被回收有两个经典的算法:引用计数法,可达性分析法
引用计数法就是给对象中添加一个引用计数器,每当有一个的地方引用它,计数器加1,当引用失效,计数器就
减1,任何时候计数器为0的对象就是不可能再被使用的,这个方法实现简单,效率高,但是现在主流的虚拟机中
没有来用这个算法来管理内存,因为它很难解决对象之间项目循环引用的问题,所谓对象之前的相互引用大的问题,
就是他们因为相互引用对方,导致他们的引用问题不能为0,所以垃圾回收无法处理他们
可达性分析算法:基本思想就是通过一系类的称为"GC Root" 的对象作为起点,从这些节点开始向下搜索,节点走过的这些路径
称为引用链,当一个对象到GC Root没有任何引用链相连的时候,则证明对象是不可用的,
JDK中应用的定义很传统:
jdk1.2之前,如果reference类型的数据存储的数值代表的是另一个内存的起始地址,就称这块内存代表一个引用
JDK1.2以后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种(引用强度逐渐减弱)
九:谈谈垃圾收集算法?
标记清除算法(标记 和 清除 主要会产生大量不连续碎片)
复制算法(算法将大小分为两块相同的区域,每次只是用其中的一块,当这块内存使用完成之后,将还存活的对象
即 不需要回收的对象,)复制到另一块去,然后把使用的空间一次性清理掉,这样回收就只对某一块进行回收
分代收集算法(这种算法就是根据对象的存活周期将内存分为几块,然后根据不同的几块选择不同的垃圾收集算法,现在的大部分 虚拟机 都是使用该算法,将堆内存分为新生代,老年代,新生代又被划分为三个区域:Eden、From Survivor、 To Survivor。这样划分使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。Minor GC(复制算法)
对象在新生代产生,新生代是 GC 收集垃圾的频繁区域,Eden区经过多次gc会慢慢被复制到From Survivor,To
Survivor区,可以简单的理解为,在Eden区的对象,如果经过3次GC还未被回收,就会被复制到From Survivor,
如果From Survivor区域满了,就会将不需要回收的对象复制到To Survivor,然后再清空FromSurvivor好比要是多次还
未被回收,改对象就会被复制到老年代,这里的参数几次几次都可以通过配置进行配置的,当然并不是所有的对象都是在
新生代生成的,有时候较大的对象 ( 即需要分配一块较大的连续内存空间 ) 则是直接进入到老年代.
(大对象就是需要大量连续内存空间的对象(比如:字符串、数组)为了避免为大对象分配内存时由于分配担保机制
带来的复制而降低效率。)Full GC 是发生在老年代的垃圾搜集算法,所采用的是标记-清除(也可以是标记整理)算法,
老年代的对象,一般是经过多次 Minor GC存活下来的对象,一般很难会被回收,举个例子,好比发生13次 Minor GC之后
才会发生一次Full GC,而且一次 Full GC 要比进行一次 Minor GC 的时间更长.如果,老年代 需要为一个很大的对象
开辟一块区域的时候,也会触发一次FullGc 堆内存大小都可以进行配置, (https://blog.csdn.net/qq_38366063/article/details/86716974) 以上只是简单概括主流的java虚拟机的回收算法,JVM 中已经实现的部分GC收集器.针对不同的区域也可以使用不同的回收算法. )
十:jvm会在什么地方进行垃圾回收的动作?
1.会在cpu空闲的时候自动回收
2.堆内存存储满
3,主动调用system.gc 后尝试回收
转载:https://blog.csdn.net/qq_38366063/article/details/88997208