概述 程序计数器,虚拟机栈,本地方法栈三个区域随线程而生,随线程而灭。栈中的栈帧随着方法的进入和退出 而有条不紊地进行着入栈和出栈操作。每个栈帧分配多少内存基本上是在类结构确定下来就已知的(尽管JIT编译器会进行一些优化,但在模型概念中基本上可以认为是在编译器就已知的),因此这几个区域的内存都具备确定性,在这几个区域内不用考虑过多的内存回收,因为方法或线程结束,内存也跟着回收。 而堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,只有在程序运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器关注的是这部分的内存。后面的分配与回收也只关注这部分的内容。
引用计数算法 引用技术算法的实现简单,判断效率也很高,在大部分情况下都是一个不错的选择,不过由于其很难解决对象之间循环引用的问题,Java中并没有使用引用计数算法来管理内存。虚拟机并不是通过引用计数算法来判断对象是否存活的。
根搜索算法 Java中通过根搜索算法判断对象是否存活。其基本思路是:使用一些列名为“GC Roots"的对象作为起点,从跟路径才是向下搜索,走过的路径称为”引用链“,当一个对象到”GC Roots“没有任何引用链相连(用图论的话说是对象到GC Roots不可达),则证明此对象是不可用的。 在Java语言中,可作为GC Roots的对象包括下列几种: 1. 虚拟机栈(栈帧中的本地变量表)中的引用的对象。 2. 方法区中的类静态属性引用的对象。 3. 方法区中的常量引用的对象。 4. 本地方法栈中的JNI中的引用的对象。
Java的引用 Java中将引用分为四种:强引用(Strong Reference),软引用(Soft Reference),弱引用(Weak Reference),虚引用(Phantom Reference)。这四种引用强度一次减弱。 强引用就是指在代码中普遍存在的类似Object obj = new Object(); 这种引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象。 软引用用来描述还有用但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围之中,并进行第二次回收。如果这次还是没有足够的内存,则会抛出内存溢出异常,在JDK1.2之后,提供了Soft Reference类来实现软引用。 弱引用也是用来描述非必须对象的,但她的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作的时候,不论当前内存是否足够,都会回收掉”只被弱引用关联的“对象。JDk1.2之后,提供Weak Reference类来实现弱引用。 虚引用也称为幽灵引用或称幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用存在,完全不会对其生存时间构成影响。也无法通过虚引用来取得一个对象实例。 在根搜索算法中不可达的对象也并非是”非死不可“的, 要宣告对象真正死亡,需要经历两次标记过程。根据Java的应用类型间接描述了堆区的内存回收机制。
方法区 一般人物方法区没有垃圾收集,Java虚拟机不要求在方法区进行垃圾收集,而且方法区的垃圾收集性价比较低,收集效率远远低于堆区。 方法区垃圾回收主要针对两部分:废弃常量和无用的类。回收废弃常量与回收Java堆中的对象非常相似。以常量池中字面量的回收为例:假如一个”abc“已经进入常量池,而没有任何String对象引用它,也没有其他地方引用它,则String会被系统清除出常量池。 类需要满足下列三个条件才算是无用的类: 1. 该类所有的实例都被回收,也就是堆中不存在该类的任何实例。 2. 加载该类的ClassLoader已经被回收。 3. 该类的Class对象没有在任何地方被引用,无法在任何地方通过反射获得该类的对象。 满足上面三个条件的类可以被虚拟机回收,不过仅仅是可以,是否进行回收,需要通过虚拟机进行设置,在大量使用反射类,动态代理等的框架中,都需要虚拟机具备类卸载功能,以保证方法区(永久代)不会溢出。
|
|