一、Java虚拟机内存分区
(1)方法区(一般称永久代)
1、所有线程共享的区域
2、主要存放类信息、常量、静态变量、运行时常量池、即时编译的代码等
(2)虚拟机栈
1、线程私有的内存区域
2、每个方法调用都会创建自己的栈帧(局部变量表,操作数栈,动态链接,方法出口等),都属于该虚拟机栈
3、栈帧中的局部变量表内存大小在编译期就完成确定,方法运行期间大小不会改变
4、当线程请求栈深度超过阈值,发生StackOverflowError,如果虚拟机栈支持动态扩展,且无法申请到足够内存会发生OOM
(3)本地方法栈
1、不同虚拟机有不同的实现、线程私有
(4)堆(一般称新生代+老年代)
1、所有线程共享的区域,所占空间最大,用于存放对象实例和数组
(5)程序计数器
1、可看作是字节码的行号指示器,每个线程都会有自己的程序计数器且互不影响,所以是线程私有的内存区域,空间较小
2、当执行native方法时,计数器值为空
3、此区域是唯一一个不会出现OutOfMemoryError情况的内存区域
二、判断对象已死算法
(1)引用计数
1、Java语言未采用该算法,它不能解决循环引用或相互引用的问题
(2)根搜索算法
1、Java和C#都采用这种算法,原理就是作用域搜索,从根开始搜索对象不可达即可回收
三、垃圾回收算法
(1)标记清除算法(可用于老年代)
缺点:效率不高、会产生大量内存碎片
(2)复制算法(主要用于新生代)
原理:将内存分为两块,每次只用一块。用完将活着的对象进行复制
HotSpot虚拟机实现:内存分为三块,一块较大的Eden区和两块较小的Survivor区; 且Eden : Survivor : Survivor = 8:1:1
分配担保策略:如果垃圾回收后存活的对象在另一块Survivor区存不下,将直接在老年代中申请内存
(3)标记整理(标记压缩)算法(可用于老年代)
原理:所有存活对象向一端移动,清理边界外的内存
(4)分代收集算法(一般和其他算法结合使用)
四、垃圾收集器
(1)Serial收集器(新生代)
单线程、工作时会暂停工作线程、简单高效、Client模式的最佳选择
(2)ParNew收集器(新生代)
Serial收集器的多线程版本、Server模式的最佳选择
(3)Parallel Scavenge收集器(新生代)
采用了复制算法、多线程、吞吐量优先
(4)Serial Old收集器(老年代)(和PS MarkSweep很相似,可以等同)
单线程、使用标记整理算法、Client模式
(5)Parallel Old收集器(老年代)
多线程、使用标记整理算法
(6)CMS收集器(老年代)
基于标记清除算法
(7)G1收集器(最新)
基于标记整理算法
五、常见虚拟机参数
(1)SurvivorRatio
新生代中Eden区域和Survivor区域容量的比值,默认为8
(2)PretenureSizeThreshold 或 MaxTenuringThreshold
直接晋升到老年代的年龄,大于这个参数直接在老年代分配内存(默认15)
(3)PermSize、MaxPermSize
永久代初始值、永久代的最大值(默认64M)
(4)-Xms、-Xmx
初始堆大小、最大堆大小
(5)NewRatio
永久代和新生代的比值
(6)-Xmn 或 NewSize
新生代大小
(7)GCTimeRatio
吞吐量,默认值99,1/(1+99)=1%,即允许1%的GC时间
(8)MaxNewSize
最大新生代大小
(9)TargetSurvivorRatio
survivor区的可使用率,当该区空间利用率达到该值时,会将对象放到老年代