JVM(3) --内存回收

那些内存需要回收

内存回收是对运行时内存区域的内存回收,其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊的执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来就已知的,因此这几个区域的内存分配和回收都具备确定性,在这几个区域就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。
而Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法的多个分支需要的内存可能也不一样,我们只有在程序运行时才知道会创建哪个对象,这部分内存的分配和回收都是动态的,垃圾收集器需要回收的内存就这堆上的内存。

哪些对象已死?哪些对象还活着

Java垃圾收集器在进行内存回收的时候,需要对内存进行判别,判断他是活着的还是已死的,即是可回收的还是不可回收的,下面是判断对象存活与否的方法。

  • 引用计数算法

    给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为0的对象就是不可能再被使用的。但是它很难解决对象间相互循环引用的问题。

  • 可达性分析算法

    在主流的商用语言(Java,c#, lisp)中是通过可达性分析算法来判断对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索搜走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明对象是不可用的。
    在Java语言中,可作为GC Roots的对象包括下面几种
  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中JNI(即一般说的native方法)引用的对象
  • 引用探索

    在java1.2以前,java中的引用的定义很传统:如果reference类型的数据中存储的是另一块内存的起始地址,就称这块内存代表着一个引用;这种定义很纯粹,但是太过于狭隘,一个对象在这种定义下只有被引用和没有被引用两种状态,对于表示一些"食之无味,弃之可惜"的对象就显得无能为力;其实我们希望还能描述其他的一些状况:当内存空间还足够时,则留在内存空间中;如果内存空间进行垃圾收集以后还是很紧张,则可以抛弃这些对象,于是我们这些对象的引用分为4个等级,4中引用强度一次削弱;
  1. 强引用:强引用在程序代码中是普遍存在的,类似“Object o = new Object()”,只要强引用还在,垃圾回收器永远不会回收这类被引用的对象;
  2. 软引用:软引用是用来描述一些还有用但是非必须的对象。对于软引用的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围内进行第二次回收。如果系统回收后还是没有足够的内存,系统将会抛出内存溢出异常,jdk1.3以后提供了SotfReference类来实现软异常。
  3. 弱引用:弱引用也是用来描述一些非必须的对象,但是它的强度比软引用还要弱一点,被弱引用关联的对象只能生存到下一次垃圾收集器之前。jdk1.2之后提供了WeakReference类实现弱引用
  4. 虚引用:目的就是能在对象被收集器回收之前收到一个系统通知。jdk1.2后提供了PhantonReference类来实现虚引用。

猜你喜欢

转载自www.cnblogs.com/curiousforcode/p/12008061.html
今日推荐