在Java开发的过程中,程序的执行需要计算机内存空间,Java并没有语法与内存创建、释放有直接联系,JVM负责管理内存的申请与释放,对于Java语言来说,显示的内存申请通常有两种:静态内存分配与动态内存分配
静态内存的分配与回收
- 静态内存分配:Java类或方法中的原始类型数据和对象的引用都是静态分配的内存,当Java编译器执行编译后就已经确定了静态内存的大小,在程序被加载后会分配静态内存且在程序运行期间内存大小不会再改变
- 静态内存回收:程序执行结束后释放、方法执行结束后释放
动态内存的分配与回收
- 动态内存分配:Java中的对象类型的数据创建是动态的内存分配,只有在程序执行的过程中才知道程序所需的内存大小
- 动态内存分配:Java中的对象不再被使用的时候内存会被回收
垃圾回收
- 什么样的对象应该被认为是垃圾需要回收?对象是否是垃圾对象取决于对象的引用类型与对象是否根路径可达
- 如何回收垃圾对象释放内存?由垃圾回收算法负责
垃圾对象
- 对象与根节点之间的联系称为引用链,当对象与根节点之间不存在引用链时,此对象成为垃圾对象,根节点可以是以下元素
- 在方法中局部变量区的对象引用
- 在Java操作栈中的对象引用
- 在常量池中的对象引用(如常量池中引用的的类名String在堆中
- 在本地方法的对象引用
- 类的Class对象(JVM加载Class时,会在堆中创建一个代表这个类的唯一数据类型的Class对象
- 若对象被软引用,当内存不足时,软引用对象为垃圾对象
- 若对象被弱引用,则此对象为垃圾对象
- 若对象被虚引用,则此对象为垃圾对象
垃圾回收算法
垃圾搜集的算法主要有三种,分别是标记-清除算法、复制算法、标记-整理算法
标记清除算法
- 概述:在程序运行期间,若可以使用的内存耗尽,GC会暂停整个程序,随后将标记存活的对象,并将堆中没被标记的对象(根路径不可达的对象)清除,最后恢复程序
- 此算法缺点:标记清除算法的主要缺点是回收后的内存空间布局是分散的,JVM必须维护空闲的内存列表
复制算法
- 概述:复制算法将内存分为两个部分,内存只分配在其中的一个位置(活动区),另一个位置始终保持空闲(空闲区)。当有效内存耗尽,GC线程停止程序,复制算法开始。GC线程将活动区的存活对象移动到内存的空闲区(按顺序排列)并清除垃圾对象。适合存活率低的对象
- 此算法缺点:1.内存浪费。2.如果对象存活100% ,则对象将会整体移动!
标记/整理算法
- 概述:标记/整理算法与标记/清除类似,只是在清除垃圾对象的同时将存活对象按地址进行了内存整理,JVM只需要维护内存的开始位置就可以方便支持后续的内存分配
- 此算法缺点:整理内存有更多的时间消耗
分代搜集算法
分代搜集算法是针对Java堆区的内存回收,是标记-清除算法、复制算法、标记-整理算法的综合实际运用
- Young区垃圾回收:当Eden区满后会触发minor GC,minor GC 会利用复制算法进行此区的内存回收
- Old区垃圾回收:当Old区满后会触发major GC or Full GC , major GC or Full GC利用 标记/清除或标记/整理算法进行内存回收
The smallest change can have the biggest impact. - Evan Treborn