JVM垃圾回收
内存结构
要想理解jvm的垃圾回收机制,必须先知道java虚拟机的内存结构。
-
程序计数器
程序计数器是一块较小的内存空间,你可以把它看成是当前线程所执行字节码文件的行号指示器。它存在的主要意义就是,在切换回当前线程时可以恢复到切换之前的状态。它也是java虚拟机中唯一没有规定任何OutOfMemoryError情况的区域。 -
java虚拟机栈
这个区域是线程私有的,主要用来存放基础类型如int,对象的引用(注意不是对象本身),局部变量。
在Java虚拟机规范中,对这个区域 规定了 两种 异常 状况: 如果 线程 请求 的 栈 深度 大于 虚拟 机 所 允许 的 深度, 将 抛出 StackOverflowError 异常; 如果 虚拟 机 栈 可以 动态 扩展, 如果 扩展 时 无法 申请 到 足够 的 内存, 就会 抛出 OutOfMemoryError 异常。 -
本地方法栈
和虚拟机栈一样,只不过主要针对native方法。 -
java堆
java堆是java虚拟机管理内存中最大的一块,它的目的是管理对象内存的分配,所以垃圾回收主要集中在堆中。它是线程共享的。 -
方法区
方法区和堆一样,也是各个线程共享的。它主要存储类信息、常量、以及静态变量、及时编译的代码。
程序计数器、虚拟机栈、本地方法栈这几块内存区域,随线程而生,随线程而灭,因此这几块区域不需要内存回收并不需要担心。
而堆和方法区中的对象都是运行时创建的,对象创建和回收都需要进行管理。
如何识别垃圾对象
要想进行垃圾回收,识别出“垃圾”很重要。在jvm中使用的是可达性分析算法进行识别。它主要是通过一个对象是否在gcRoots对象的引用链中来确定对象是否需要回收的。而GcRoot主要包括:栈帧中的变量(方法中的局部变量)、方法区中的常量、方法区中的静态变量、jni中引用的对象。
垃圾回收算法
识别出内存中无用对象以后,就需要进行清理,主要的垃圾回收算法主要有三种。
-
标记-清理算法
这种算法主要是先标记出无用对象,在一次性清理掉他们。这种算法有两大弊端,首先效率上标记和清理都不算高效操作,第二内存上,这样会产生大量的不连续内存,空间利用率不高 -
复制算法
这种算法将内存分为两块,每次垃圾回收时将有用内存移入另一块内存中,然后清空这一侧的内存。这种算法,浪费了一半的内存空间。 -
标记-整理算法
这种算法标记过程和标记清理算法很像,但是在清理时会将存活对象都像一段移动,然后直接清理掉端边界以外的内存空间。 -
分代回收算法
该算法,将内存分为年轻代和老年代,针对他们不同的特点采用不同回收算法,在年轻代中大部分对象都是朝生夕死,因此采用复制算法,将内存分为eden区和两块survivor区,一般按8:1:1的比例分配,内存分配主要在eden区和其中一块survivor区中,当进行垃圾回收时,将存活内存移至另一块survivor区中,当另一块survivor区内存不够时,会临时存入老年代中。在老年代中的对象都死生命周期很长的,因此采用标记清理或标记整理算法进行垃圾回收。
网友评论