第二部分:JVM内存区域
一:组成部分
方法区还包含如下:
加载的类信息、常量、静态变量、即时编译器编译后的代码等、运行时常量;
运行时常量,例如String中的intern()方法,如果String查找常量池中对象存在,就直接返回String对象;如果常量池中不存在,就把它添加到常量池中;
二:对象访问是如何进行的?
主流的访问方式:使用句柄和直接指针;
例如:eclipse设置显示GC,模拟java堆溢出
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
设置最大方法区大小
-XX:+MaxPermSize
三:异常类型
1:java堆溢出
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
2:虚拟机栈何本地方法栈溢出
-Xss128k
3:运行时常量池溢出
-XX:PermSize=10M -XX:MaxPermSize=10M
4:方法区溢出
-XX:PermSize=10M -XX:MaxPermSize=10M
5:本地直接内存溢出
-XX:MaxDirectMemorySize=10M
第三部分:垃圾收集器与内存分配策略
一:如何判断“对象”已死?
一般解决方案:引用计数算法,当一个地方引用它,计数器就加1;当引用失效时,计数器就减1,直到计数器为0,就表示这个对象已死,可以调用GC进行垃圾回收;
java垃圾收集器是采用"根搜索算法":
二:引用类型:(引用类型从强到弱顺序排列)
A:强引用
B:软引用
C:弱引用
D:虚引用
三:对象由“生”到“死”生命周期:
1: “生存的对象” -----通过“根搜索算法”判断 --------》2:第一次标记并且进行一次筛选此对象是否有必要执行finallize()(筛选条件:A:如果没有覆写finalize方法;B:JVM虚拟机已经调用过了finalize方法),虚拟机就会判断没有必要执行;
2:如果虚拟机判断有必要执行的时候,就会把对象会放置到F-Queue中,稍后GC将对F-Queue队列进行第二次小规模标记;
注意:finallize()方法系统只调用一次,如果调用多次,系统不会执行;
四:垃圾收集算法:
A:标记-清除算法 缺点:1:效率低;2:空间问题---会产生大量不连续的内存碎片,难以回收;
B:复制算法 ----修正“标记--清除算法缺点”,例如JVM中的Eden、两个Survivor,把其中的一个Survivor中一些存活的对象负责到另一个Survivor中,然后直接回收第一个Survivor内存块;然后交替执行,如果另一个Survivor内存空间比复制的对象内存小,就需要用到老生代中的内存;
C:标记-整理算法
D:分代收集算法
五:垃圾收集器
A:Serial收集器 ---单线程原理工作
B:ParNew收集器-----多线程Serial收集器实现,可以通过-XX:ParallelGCThreads参数来限制垃圾收集的线程数;
C:Parallel Scavenge收集器---一款新生代收集器,
控制吞吐量参数:1:控制最大垃圾收集停留时间为-XX:MaxGCPauseMillis参数;2:直接设置吞吐量大小的-XX:GCTimeRatio参数
还有一个重要的参数:-XX:+UseAdaptiveSizePolicy,这是一个开关参数,这个参数打开以后,就不需要指定新生代的大小、Eden与Survivor区的比例、晋升老年代对象年龄等细节参数设置;
D:Serial Old收集器-----是Serial老生代收集器
E:Parallel Old收集器---是Parallel Scavenge收集器的老生代版本
F:CMS收集器----是一种以获取最短回收停顿时间为目标的收集器,目前应用于B/S系统的服务器上。整个过程分以下4个步骤:
1:初始标记
2:并发标记
3:重新标记
4:并发清除
参数-XX:CMSFullGCsBeforeCompaction这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次压缩的。
G:G1收集器
六:内存分配与回收策略
1:对象优先在Eden分配
2:大对象直接进入老年代
3:长期存活的对象将进入老年代
可以通过参数-XX:MaxTenuringThreshold来设置,默认为15岁,从Eden中到Survivor区每熬过一次Minor GC,年龄就加一岁;
4:动态对象年龄判定
5:空间分配担保
通过参数-XX:HandlePromotionFailure=false来设置,直接进行Full GC;