Java内存管理中的程序计数器、虚拟机栈、本地方法栈都是随线程的建立而建立,随线程的结束而结束;栈中的栈帧随着方法的进入和退出执行入栈和出栈的工作。每一个栈帧分配多少内存是根据类结构来定的,因此这几个区域的内存分配与回收具备确定性,不是考虑垃圾回收的范围。
Java的垃圾回收主要是指Java堆和方法区的内存回收,只有在运行时才知道需要多少内存,需要创建哪些对象,这部分的内存分配和回收是动态进行的。
如何判断对象是否已经死亡?
1、引用计数法
给对象添加一个引用计数器,每当一个地方引用它时,计数器值+1;当引用失效时,计数器-1;任何时刻计数器为0的对象就是不可能再被使用的。(声明新对象的时候计数器为0,给对象new个实例的时候计数器为1。)
Reference obj1 = new Reference();//obj1的引用数为1
Reference obj2 = new Reference();//obj2的引用数为1
obj1 = obj2;
//obj2的引用数为2
2、可达性分析算法
基本思想是通过一系列的称为GC Root的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到到GC Root没有任何引用链相连,则证明此对象是不可用的。
在Java语言中,可作为GC Roots的对象包括以下几种:虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(Native方法)引用的对象。
3、新的引用计数法
无论是通过引用计数算法判断对象的引用数量还是通过可达性判断对象的引用链是否可达,如果希望描述一类:当内存空间还足够时则能够保留在内存之中;如果内存空间在进行垃圾收集后还是非常紧张则抛弃的对象。
JDK1.2之后对引用的概念做了扩充,分为强引用、软引用、弱引用和虚引用4种。
强引用(StrongReference):Object o = new Object();
软引用(SoftReference):如果内存够用就不回收,如果回收1次还发现不够用就再回收一次;
弱引用(WeakReference):被弱引用关联的对象只能生存到下一次垃圾收集发生之前。
虚引用(PhantomReference):无法通过虚引用来取得一个对象实例,只会在该对象被收集器回收时收到一个系统通知。
4、生存还是死亡
即使是不可达对象也并非非死不可的对象,真正宣告死亡要经历两个过程:如果发现对象没有和GC Root链接,它就会被第一次标记并进行筛选,如果对象有覆盖finalize()方法,当对象没有覆盖finalize()方法或者已经执行过finalize()方法,则抛弃之。如果有就放到F-Queue队列中,等待执行finalize()。
5、回收方法区
永久代的回收效率没有新生代回收率高,但是JVM也会做这部分的回收工作。永久代的垃圾主要有两部分内容:废弃常量和无用的类。常量回收:如果没有任何一个变量引用常量值则必要时将其清理出内存区;无用的类:需要满足3个条件,1该类的所有实例都已经被回收2加载该类的ClassLoader已经被回收3该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。