面试题jvm

948 阅读8分钟
说一下 jvm 的主要组成部分?及其作用?

堆,方法区,虚拟机栈,本地方法栈,程序计数器 堆。 堆是Java对象的存储区域,任何用new字段分配的Java对象实例和数组,都被分配在堆上,Java堆可使用-Xms -Xmx进行内存控制,值得一提的是从JDK1.7版本之后,运行时常量池从方法区移到了堆上。 方法区。它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,方法区在JDK1.7版本及以前被称为永久代,从JDK1.8永久代被移除。 虚拟机栈。虚拟机栈中执行每个方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。 本地方法栈。与虚拟机栈发挥的作用相似,相比于虚拟机栈为Java方法服务,本地方法栈为虚拟机使用的Native方法服务,执行每个本地方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。 程序计数器。指示Java虚拟机下一条需要执行的字节码指令。 以上五个区域是Java虚拟机内存划分情况,其中方法区和堆被JVM中多个线程共享,比如类的静态常量就被存放在方法区,供类对象之间共享,虚拟机栈,本地方法栈,pc寄存器是每个线程独立拥有的,不会与其他线程共享。 所以Java在通过new创建一个类对象实例的时候,一方面会在虚拟机栈中创建一个该对象的引用,另一方面会在堆上创建类对象的实例,然后将对象引用指向该对象的实例。对象引用存放在每一个方法对应的栈帧中。

说一下 jvm 运行时数据区?

线程私有的数据区     程序计数器     虚拟机栈     本地方法栈   所有线程共有的数据区     Java堆     方法区     

队列和栈是什么?有什么区别?

栈(Stack)是限定只能在表的一端进行插入和删除操作的线性表。 队列(Queue)是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。

类加载器

常用的类加载器:

Bootstrap ClassLoader Extension ClassLoader ApplicationClassLoader。

类和类加载器 类加载器拥有自己独立的命名空间,两个类是否相等(instanceof),只有在这两个类是同一个类加载器加载的才有意义

什么是双亲委派模型?

双亲委派模型: 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。这一点是从安全角度考虑的,试想如果有人编写了一个恶意的基础类(如java.lang.String)并装载到JVM中将会引起多么可怕的后果。但是由于有了“全盘负责委托机制”,java.lang.String永远是由根装载器来装载的,这样就避免了上述事件的发生。

怎么判断对象是否可以被回收?

引用计数法,根搜索法, jvm中使用的 是根搜索算法。通过一系列的名为“GC Root”的对象作为起点,从这些节点向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GCRoot没有任何引用链相连时,则该对象不可达,该对象是不可使用的,垃圾收集器将回收其所占的内存。

java 中都有哪些引用类型?

强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)

说一下 jvm 有哪些垃圾回收算法?

标记-清除、复制、标记-整理和分代收集 新生代中对象的存活周期短,只有少量存活的对象,所以可以使用复制算法,而老年代中对象存活时间长,而且对象比较多,所以可以采用标记-清除和标记-整理算法。

说一下堆和栈的区别

栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。

说一下 jvm 有哪些垃圾回收器?

新生代收集器:Serial、ParNew、Parallel Scavenge

老年代收集器:CMS、Serial Old、Parallel Old

整堆收集器: G1

详细介绍一下 CMS 垃圾回收器?

CMS收集器是为了低延迟而生,通过尽可能的并行执行垃圾回收的几个阶段来把延迟控制到最低。CMS收集器是老年代的垃圾收集器,一般情况下会有ParNew来配合执行(默认情况下也是ParNew),ParNew也是使用并行的算法来执行年轻代的回收。当然除此之外,你还可以选择使用Serial收集器来收集年轻代,不过一般很少这样使用。通过咱们说的CMS收集器是指广义上的CMS收集器,包含以下几个:ParNew(Young)GC + CMS(Old)GC + Serial GC 算法(应对核心的CMS GC某些时候的不赶趟,开销很大)。 blog.csdn.net/mc90716/art…

新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

新生代收集器:Serial、ParNew、Parallel Scavenge

老年代收集器:CMS、Serial Old、Parallel Old

简述分代垃圾回收器是怎么工作的?

一般来说 gc类型有两种 Scavenge GC

一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

Full GC

对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

· 年老代(Tenured)被写满

· 持久代(Perm)被写满

· System.gc()被显示调用

·上一次GC之后Heap的各域分配策略动态变化

jvm调优工具

jconsole、 JProfiler

jvm调优常用参数

-Xmx:最大JVM可用内存, 例:-Xmx4g

-Xms:最小JVM可用内存, 例:Xms4g

-Xmn:年轻代内存大小,例:-Xmn2560m

-XX:PermSize:永久代内存大小,该值太大会导致fullGC时间过长,太小将增加fullGC频率,例:-XX:PermSize=128m

-Xss:线程栈大小,太大将导致JVM可建的线程数量减少,例:-Xss256k

-XX:+DisableExplicitGC:禁止手动fullGC,如果配置,则System.gc()将无效,比如在为DirectByteBuffer分配空间过程中发现直接内存不足时会显式调用System.gc()

-XX:+UseConcMarkSweepGC:一般PermGen是不会被GC,如果希望PermGen永久代也能被GC,则需要配置该参数

-XX:+CMSParallelRemarkEnabled:GC进行时标记可回收对象时可以并行remark-XX:+UseCMSCompactAtFullCollection 表示在fullGC之后进行压缩,CMS默认不压缩空间

-XX:LargePageSizeInBytes:为java堆内存设置内存页大小,例:-XX:LargePageSizeInBytes=128m

-XX:+UseFastAccessorMethods:对原始类型进行快速优化

-XX:+UseCMSInitiatingOccupancyOnly:关闭预期开始的晋升率的统计

-XX:CMSInitiatingOccupancyFraction:使用cms作为垃圾回收,并设置GC百分比,例:-XX:CMSInitiatingOccupancyFraction=70(使用70%后开始CMS收集)

-XX:+PrintGCDetails:打印GC的详细信息

-XX:+PrintGCDateStamps:打印GC的时间戳

-Xloggc:指定GC文件路径