每个java程序在运行时都会启动一个java虚拟机,jvm把内存分为两类共5个部分:
线程共享区域:
方法区(Method Area):用于存储类信息,常量,静态变量和.class文件。
堆(Heap):只用于存储对象实例,这里是垃圾收集器主要收集的区域。
线程私有区域:
程序计数器(Program Counter Stack):每个线程都需要一个独立的程序计数器。
虚拟机栈(VM Stack):执行java方法的栈内存,在函数中定义的基本类型变量和引用变量都存储在这里。线程执行离开变量的作用域后,该内存空间即被释放。
本地方法栈(Native Method Stack):执行本地方法的栈内存。
当一个对象没有引用指向它时,它就变成了垃圾。java不提供显示分配和删除内存的方法(但是可以通过把对象引用置为null来释放内存),它有一套在后台运行的垃圾回收机制。
在java中判断对象是否存活采用可达性分析算法(根搜索算法):程序把所有的引用关系看作是一张图。从一个节点GCROOT开始,如果一个节点与GCROOT之间没有引用链存在,则该节点视为垃圾回收的对象。
java的多采用分代垃圾回收方式:它将内存划分为年轻代和老年代。年轻代用于存储新创建的对象,这里的大多数对象会在短时间内变得不可达。年轻代总共有三块区域,1块为Eden区,2块为区Survivor。各个空间的执行顺序如下:
1.绝大多数创建的对象分配在Eden区。
2.在Eden区发生一次GC后,存活的对象被分配到其中一个Survivor区中。
3.一旦一个Survivor区满,则将存活对象移动导另一个Survivor区,并将已满的Survivor区清空。
4.重复多次上述步骤后依旧存活的对象将被移动到老年区。
没有变得不可达,存活下来的对象被复制到老年区。老年区的空间更大,回收频率更低。老年区采用标记-整理(Mark-Compack)算法:在完成标记后,将存活的对象都向一端移动,然后清理掉端边界以外的内存。