【复习笔记】每次面阿里都会问到的JVM相关知识

来源:互联网 发布:苹果6s怎么设置4g网络 编辑:程序博客网 时间:2024/06/03 22:08

一、JVM内存模型

JVM将内存划分为:程序计数器,java虚拟机栈,java堆,方法区,本地方法栈。

程序计数器(PC):记录字节码执行到的位置,即标识程序执行到什么地方了。——线程独享

java虚拟机栈,主要存储栈帧(局部变量表,方法出口等信息)。——线程独享

java堆,存储对象的实例,也是GC主要发生的地方。——线程共享

方法区,存储静态变量,常量以及类加载等信息。——线程共享

本地方法栈,执行native方法的服务。——线程共享 这个其实并不知道是干啥的。

二、OOM

OutOfMemoryError不属于Exception,而继承自ErrorThrowable。此类错误可以发生在堆中,也可以发生在栈中。

堆中的OOM:当产生足够数量的对象实例而不发生GC时,就会发生OOM。比如循环产生实例对象放入一个ArrayList中,循环足够多次时就会发生OOM。

出现的关键字为:java.lang.OutOfMemoryError: Java heap space

栈中的OOM:因为每个线程都独享一个java虚拟机栈来记录各自的栈帧,所以当产生的线程足够多的时候,或者将虚拟机参数Xss(每个线程的栈空间)调大,当总内存超过了jvm分配的栈内存的时候,就会发生OOM。

出现的关键字为:java.lang.OutOfMemoryError:unable to create new native thread

栈中的StackOverFlow:当不断递归调用某线程内的方法时,会不断产生栈帧,累积超过虚拟机允许的最大值时,就会发生SOF。

出现的关键字为:java.lang.StackOverflowError。

三、GC策略

最垃圾的也没人用的:引用计数法,没法对循环引用的对象进行回收。一个简单的例子:

public class sample{public sample sampleMenber;public static void main(String [] args){sample stest = new sample();stest.sampleMenber = stest;stest = null;}}
stest置为空的时候,应该进行回收,但因为存在实例变量引用的计数,依然不会被回收。所以不好。

根搜索算法,在虚拟机中有几种引用被称为根引用,当任意一个根引用都无法到达某一对象时,这个对象是可以被回收的。

在java中所谓根引用(GC ROOT)有以下几种:

1)java栈中的局部引用

2)方法区中的静态引用

3)方法区中的常量引用

四、垃圾收集算法

标记-清除算法:

1)标记,使用跟搜索算法找到不可达的对象,然后将其标记。

2)清除,将上一步标记过的所有对象进行清除。

缺点:在用这种算法进行GC时,必须暂停其他的线程,因为如果不暂停其他的线程,可能会引发对象状态的改变,有些对象在GC时又变成可回收的了。这样效率就会非常低。而且当删除的对象在内存中不连续时,对象的存储就会变成碎片,不好管理。

复制算法:

把内存等分成两半,然后进行GC时把存活的对象从第一半内存复制到第二半,再进行GC时,再从第二半复制到第一半。

优点:优化了标记-清除算法效率低下的问题,并且不会造成内存碎片,在两个内存区复制时,对象是被整齐排列的。

缺点:8G内存直接变成了4G可用。

标记-整理算法

第一步标记,与标记-清除算法相同,通过跟搜索算法找到存活的对象。

第二步整理,把存活的对象从内存起点开始整齐排列,排列之后的末尾之后的内存一次性清空。

优点:优化了复制算法浪费一半内存的缺点,同时不会产生内存对象排列分散的缺点。但是它也有缺点就是效率依然比较低,相比于复制算法效率要低一些。

分代收集算法

将内存划分为:新生代,老年代,永生代。其中新生代又分为:eden,s0,s1。新生代中eden区占80%左右,s0 s1分别占10%左右。

最开始的对象在eden区中产生,当可用内存不足时,发生GC,把eden区中存活的对象移动置s0,之后eden区中又产生对象,当再一次发生GC时,eden区中的存活对象与s0区中的存活对象一起复制到s1区,之后eden区再次产生对象....总结来说,新生代使用的GC算法是复制算法,在s0 s1两个区之间来回复制。当在新生代经历过GC的次数超过JVM设定的值时,这些对象将会被移动到老年代。而在老年代中,使用的GC算法则是标记-整理。

原创粉丝点击