1.JVM内存分区
1)程序计数器:程序计数器是当前线程所执行字节码的行号指示器,是私有的。如果执行的是非native方法,程序计数器保存的是当前要执行的指令的地址;如果是native方法,则程序计数器中的值是undefined。作用:保证线程切换后能恢复到正确的运行位置
2)虚拟机栈:是线程私有的,生命周期与线程相同。Java方法执行时会创建一个栈帧,存放局部变量表,操作栈,动态链接,方法出口等信息。
局部变量表存放的是8种已知的基本数据类型,对象的引用和指令地址,一般在编译期就完成分配。当线程请求的栈深度超过超过虚拟机所允许的栈深度就会抛出StackOverFlowError,当虚拟机栈动态扩展,申请不到足够的内存空间时,就会抛出OutOfMemoryError
3)本地方法栈:作用同虚拟机栈,只是为native方法服务(native方法,非Java语言写的方法,一般为C/C++编写的代码)
4)堆:Java虚拟机内存管理中最大的一块,是所有线程共享的一个内存区域,在虚拟机启动时就创建,存放对象实例。这一部分是垃圾回收器管理的主要区域。
一般划分为一块Eden和两块Survivor,默认大小为8:1:1
5)方法区:和Java堆一样是线程共享的,存放类加载信息、常量和静态变量,即时编译器编译后的代码等。对于HotSpot虚拟机来说,这一块也是GC回收的范围。
方法区中有一个区域是运行时常量池,存放编译期生成的各种字面量和符号引用。Java虚拟机对Class文件的每一部分的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。但对于运行时常量池,Java虚拟机没有做任何细节要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。
2.GC回收算法
这里只介绍几个常见的GC算法
判断是否为垃圾
1)引用计数法:堆中的每个对象对应一个引用计数器(初始值为1),当对象被赋予任何变量时引用计数器加1,当某个变量引用不在作用域则减1。引用计数器减到0时则可以将对象回收。实际中使用较少,微软的COM技术就使用了引用计数法。缺点:无法解决循环引用的问题,A引用B,B引用A,但无任何其他引用A或B
2)根搜索算法(HotSpot虚拟机采用的方式)
从“GC Roots"开始,向下搜索,走过的路径称为引用链。一个对象到GC Roots没有任何引用链则不可到达对象。
可以作为GC Roots的对象:
虚拟机栈中引用的对象
方法区中静态变量引用的对象
方法区中常量引用的对象
本地方法栈中JNI引用的对象
回收方法区,主要回收两部分内容:废弃常量和无用的类。
废弃常量:没有被任何对象引用常量池中的常量
无用的类:
1)该类的所有实例已经被回收
2)加载该类的ClassLoader已经被回收
3)该类的java.lang.Class对象没有在任何其他地方被引用
几种常见的GC算法
1)标记-清除算法:首先标记出所有需要回收的对象(使用根搜索算法进行两次标记),然后进行回收。
缺点:容易产生大量内存碎片。
2)复制算法:
Eden和一块Survivor的存活对象拷贝到另一块Survivor上,当Survivor空间不够则进入老年代。
复制算法适用于新生代,因为垃圾对象多于存活对象,复制算法更高效
优点:解决了内存碎片问题,但是内存折半。(图片引用http://www.cnblogs.com/AloneSword/p/4262255.html)
3)标记-整理算法:
结合前两个算法的优点,适合用于
老年代的算法(存活对象多于垃圾对象)。
标记后不复制,而是将存活对象压缩到内存的一端,然后清理边界外的所有对象。
4)分代回收算法:
对不同内存区域采用不同的回收算法,一般区分老年代和新生代。
附:常见垃圾收集器介绍
1)Serial收集器是最基本、历史最悠久的垃圾收集器,它是一个单线程的收集器。进行垃圾回收时,必须暂停其他所有的工作线程,直到它收集结束。优点是高效简单,适用于用户桌面应用的虚拟机。
2)Parallel Scavenge收集器是一个新生代收集器,也是一个使用复制算法的收集器,又是并行的多线程的收集器。它的关注点与其他收集器不同,CMS收集器等关注的是尽可能缩短垃圾收集时用户线程的停顿时间,适用于与用户交互的程序,但它关注的是吞吐量(吞吐量=用户代码运行时间/(用户代码运行时间+垃圾收集时间)),适用的是后台运算的程序。
3)CMS收集器,基于“标记-清除”算法实现,运作过程分为四个步骤:初始标记、并发标记、重新标记和并发清除。初始标记只标记和GC Roots直接关联的对象,并发标记就是进行GC Roots Tracing的过程,而重新标记则是对并发标记期间由于用户程序继续运行而导致标记产生变动的那一部分对象的标记记录的修正,并发清除就是进行垃圾回收了。最大的特点是最短停顿回收时间。
4)G1收集器,基于“标记-整理”算法,不会产生内存碎片,而且能够精确的控制停顿(将Java堆划分为很多大小固定的区域,并且跟踪这些区域的垃圾堆积程度,每次优先回收垃圾最多的区域)。