自问自答学习JVM(一)

108 阅读5分钟

【1】JVM的内存模型


JVM的内存由虚拟机栈、本地方法栈、程序计数器、堆、方法区组成。在
HotSpot虚拟机中将虚拟机栈和本地方法栈合二为一了。

线程私有区域:虚拟机栈、本地方法栈、程序计数器

线程共享区域:堆、方法区

HotSpot虚拟机内存模型:


程序计数器:用于记录当前执行字节码指令的地址。如果执行的native方法,则为null。

虚拟机栈:每个方法在执行的时候也会创建一个栈帧,存储了局部变量,操作数,方法返回地址。每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。通常所说的栈,一般是指在虚拟机栈中的局部变量部分。如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。

本地方法栈:和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。也会抛出StackOverflowError和OutOfMemoryError。

堆:在虚拟机启动的时候创建,用于存放对象实例以及数组。当堆中没有内存可分配给实例,也无法再扩展时,则抛出OutOfMemoryError。

方法区:用于存储已经被虚拟机加载的常量,类信息,静态元素等。

【3】JVM内存

JVM内存可以划分为堆内存和非堆内存。堆内存可以细分为年轻代、老年代。

年轻代组成:Eden、From Survivor、To Survivor。年轻代内存比例为8:1:1。

老年代组成:Tentired。


非堆内存就是一个永久代。在JDK1.8版本废弃了永久代,替代的是元空间(MetaSpace),元空间与永久代类似,都是方法区的实现,他们最大区别是:元空间并不在JVM中,而是使用本地内存。

详细JVM内存图:


【4】堆内存和非堆内存的作用

堆内存的作用就是存放对象和数组。

非堆内存的作用就是存放程序运行过程中长期存在的对象,比如类信息、静态元素、常量。

【5】垃圾回收算法有哪些

1.标记-清除算法

2.复制算法

3.标记-整理算法

4.分代收集算法


该算法分为
标记-清除算法

“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它是最基础的收集算法,后续的算法都是对其不足进行改进得到。这种垃圾收集算法会带来两个明显的问题:

1、效率问题

2、空间问题(标记清除后会产生大量不连续的内存碎片)


复制算法

为了解决“标记-清除”算法的效率问题,“复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。


不足之处:

1、需要消耗一般的堆内存空间,内存利用率不高。

标记-整理算法

为了解决“标记-清除”算法的空间问题,提出了“标记-整理”算法,标记过程仍然与“标记-清除
”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。


分代收集算法

当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择

“标记-清除”或“标记-整理”算法进行垃圾收集。

7HotSpot为什么要分为新生代和老年代?

根据上面的对分代收集算法的介绍回答。

【8】MinorGC、FullGC什么时候触发?

MinorGC触发(新生代GC,包含所有在新生代工作的收集器):

1.当Eden内存满了,需要将存活对象复制到S0内存中时。

2.当需要将Eden和S0内存中的存活对象复制到S1内存中时。

FullGC触发(老年代GC,包含所有在老年代工作的收集器):

1.当老年代空间不足。

2.当持久带空间不足。

3.堆中分配很大对象时。

4.程序显示调用System.gc()方法。

【9】什么是垃圾

内存中已经不再被使用到的空间就是垃圾

【10】要进行垃圾回收,如何判断一个对象是否可以被回收?

1.引用计数法

很难解决对象之间的循环引用问题

2.枚举根节点做可达性分析

通过一系列名为“GC Roots”的对象作为起始点,从“GC Roots”对象开始向下搜索,如果一个对象到“GC Roots”没有任何引用链相连,说明此对象可以被回收。


【11】哪些对象可以作为GC Roots的对象:

1.虚拟机栈中局部变量(也叫局部变量表)中引用的对象

2.方法区中类的静态变量、常量引用的对象

3.本地方法栈中JNI (Native方法)引用的对象