一、java运行时数据区域
1、方法区:各个线程共享的内存区域,已加载的类信息、常量、静态变量、即时编译后的代码区域。
2、堆:是被所有线程共享的一块内存区域,在虚拟机启动时创建,存放对象的实例。OutOfMemoryError。-Xmx -Xms 控制大小,一般大小一致,否则会导致频繁回收堆内存。
3、虚拟机栈:java方法执行的内存模型:每个方法执行的同时,会创建一个栈帧。每一个方法从调用直至执行完成的过程,对应着栈帧在虚拟机栈中的如栈和出栈。如果线程请求的栈的深度大于虚拟机栈所允许的深度则stackOverflowError;如果虚拟机栈可动态扩展,如果扩展时无法申请到足够的内存,则OutOfMemoryError
4、程序计数器:当前线程所执行的字节码的信号指示灯,线程私有
5、本地方法栈:Native方法
6、运行时常量池:用于存放编译期生成的各种字面量和符号的引用,类加载后进入方法区的运行时常量池存放,OutOfMemoryError
二、垃圾收集器和内存分配策略
1、已死对象
1)引用计数算法:给对象中添加一个引用计数器,每当有地方引用它时,计数器加1,;当引用失效时,计数器减一;任何时刻计数器为0时对象就不能再被使用。缺点:无法解决相互引用
2)可达性分析算法:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连,当一个对象到GC Roots没有任何引用链相连时,则证明此对象不可用。
GC Roots对象:a)虚拟机栈中引用的对象 b)方法区中类静态属性引用的对象 c)方法区中常量引用的对象 d)本地方法栈中JNI引用的对象
2、四种引用
1)强引用:new Object()
2)软引用:在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收
3)弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生之前
4)虚引用:一个对象是否有虚引用的存在完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象的实例。
三、垃圾回收算法
1、标记清除算法:首先标记出所有需要回收的对象,在标记完后统一回收所有被标记的对象
2、复制算法:(年轻代Eden:Survivor1:Survivor2=8:1:1)将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存使用完了,就将还存活的对象复制到另外一块上面,然后把使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可
3、标记-整理算法:(老年代)先标记,然后不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉边界以外的内存
4、分代收集算法:根据对象存活周期不同,将内存分为几块。一般是将java堆分为年轻代和老年代。在年轻代中,每次收集时都有大批对象死去,只有少量存活,用复制算法。老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理或标记-整理。
四、内存分配和回收策略
1、新生代GC:Minor GC
2、老年代GC:Major GC/Full GC