JVM知识总结(一)——学习笔记之内存管理

参考周志明的《深入理解Java虚拟机》

一、JVM的五大内存区域

1.程序计数器

     程序计数器是一块内存叫小的内存空间,可以看作当前线程所执行的字节码的行号指示器,分支,循环,跳转,异常处理,线程恢复等功能都需要这个计数器来完成。因为各个线程之间的计数器互不影响,独立存储,所以其属于“线程的内存”。

2.Java堆

    Java堆主要是用来存放实例对象的,是垃圾收集器管理的主要区域。

3.方法区

    方法区主要用于存储已被虚拟机加载的类信息,常量,静态变量。与Java堆一样,是各个线程共享的区域。

4.Java虚拟机栈

    Java虚拟机栈描述的是Java方法的内存模型,每个方法在执行时都会创建一个栈帧,用来存储局部变量,操作数栈,方法的出入口信息(方法的参数列表及返回值),每一个方法从调用到执行完成就对应值,一个栈帧在虚拟机栈从入栈到出栈的过程。属于“线程私有的内存”

5.本地方法栈

    与虚拟机栈发挥的作用是十分类似的,只不过虚拟机栈是为虚拟机执行的Java方法提供服务,而本地的方法栈则是为虚拟机使用到的Native方法提供服务。

二、如何判断对象是否存活

1、引用计数法

    给对象添加一个引用计数器,每当有一个地方引用它是,计数器加一,每当引用失效时,计数器值减一,当计数器的值为零时,则判断这个对象不可能被引用。

2.可达性分析算法

    将被称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索其“引用链”,如果所有的对象都不包含某一个对象,则这个对象则可以被判断为可被回收的,如下图所示,虽然Object5,Object6,Object7之间存在引用,但不在“GC Roots”的引用链中,所以Object5,Object6,Object7是可回收的。

三、垃圾收集算法

    1.标记-清除算法

     该算法分为两个阶段,即“标记”和“清除”,首先先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,采用这种算法主要存在两个问题,一是标记和清除的效率都不高,二是会产生大量不连续的空间碎片。   

    2.复制算法

    该算法将内存分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另一块内存,然后再将之前使用过的那块内存清理。这种方法实现简单,运行高效,但是内存只能使用一半,浪费的内存实在是太高了。在新生代中,该区域中的对象98%是“朝生夕死”的,所以并不需要按照1:1来划分内存空间,而是将内存划分成一块较大的区域(Eden)和两块较小的区域(Survivor),在回收时,将存活的对象复制到另一块Survivor上,在HotSpot中Eden和Srivivor的比值默认为8:1,这样的话只有10%的内存会被浪费。这种算法当对象的存活率较高时,会进行大量的复制操作,效率较低。

    3.标记-整理算法

    该算法首先标记出所有存活的对象,然后将所有存活的对象都向一端移动,然后直接清理端边界以外的内存。这样虽然会尽量的避免了内存碎片的产生和内存的浪费,但是当对象存活率较高时,仍会进行大量的复制操作,效率较低。该算法虽然与复制算法有些相似,但相比于复制算法,标记-整理算法的执行效率要低。

四、内存回收与分配策略

    1.分配策略

    分配的规则不是100%固定,其细节取决于当前使用的哪一种垃圾收集器,以及虚拟机中与内存相关的参数的设置。

    (1)对象优先在Eden上分配

    (2)大对象直接进入老年代,可以通过-XX:PretenureSizeThreshold参数来设置。

    (3)长期存活的对象将进入老年代,即对象在新生代中每“熬过”一次MinorGC(复制算法的回收,用于新生代内存回收),其年龄加一,当年龄达到一定的值(默认15)是,该对象将进入老年代,这个值可以通过参数-XX:MaxTenuringThreshold来设置。

    (4)动态的年龄判断,如果在Survivor空间中的对象中相同年龄的所有对象的总和大于Survivor空间的一半,则年龄大于或等于该年龄的对象将会进入老年代,不需要等到-XX:MaxTenuringThreshold中要求的年龄。

2.回收策略

    在发生MinorGC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果这个条件成立,那么MinorGC,即为安全的;如果不成立,测虚拟机会查看HandlePromtionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次MinorGC,如果发生了担保失败,就会在担保失败后重新发起一次FullGC;如果小于或者HandlePromtionFailure设置为不允许担保失败,则需要进行一次FullGC。

猜你喜欢

转载自blog.csdn.net/weixin_41682049/article/details/87870127
今日推荐