zoukankan      html  css  js  c++  java
  • 第三章垃圾收集器和内存分配策略

    1. 概述

    第二章介绍了Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生 随线程而死。栈中的栈帧随着方法的进入和退出而有条不紊地进行着出栈入栈的操作,每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的(尽管JIT会进行优化,但本章基于概念模型的讨论中,大体上认为是编译期可知)。因此这几个区域的内存分配和回收都具有确定性,不需要过多考虑回收问题,因为方法结束或线程结束时,内存自然就跟着回收了。

     

    Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间时才知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的就是这部分内存,本章后续讨论的内存分配和回收也仅指这一部分内存。

     

    1. 确定对象"存活"与"死去"

    前言:要想垃圾回收,首先就得确定哪些对象活着,哪些已经"死去"。

    (1)引用计数算法

    2.1.1介绍

    给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1,;任何时刻计数器为0的对象就是不可能再被使用的。

    客观的说,引用计数算法的实现简单,判定效率也很高,在部分情况下不错,但至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间的互相循环引用的问题

    2.1.2举例

    class testClass{

        public Object instance = null;

    }

     

    public class GcTest {

     

        public static void main(String[] args) {

            

            testClass testA = new testClass();

            testClass testB = new testClass();

            

            testA.instance = testB;

            testB.instance = testA;

            

            testA = null;

            testB = null;

            

            System.gc();

     

        }

     

    }

    2.1.3结论

    上述代码运行结果 GC日志表明,虚拟机并没有因为这两个对象互相引用就不回收它们,这也从侧面说明了虚拟机并不是通过引用计数算法来判断对象是否存活的。

    (2)可达性分析算法

    2.2.1现状

    在主流的商用程序语言(Java,C#)的主流实现中都是通过可达性分析来判定对象是否存活的。

    2.2.2介绍

    通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象时不可用的。比如下方,5,6,7虽然互相有关联,但是它们到GC Roots是不可达的,所以会判定为是可回收对象(也解释了上面的代码)

    2.2.3进一步

    在Java语言中,可作为GC Roots的对象包括下面几种

    **虚拟机栈(栈帧中的本地变量表(就是局部变量表,都是local Variable的翻译))中引用的对象

    **方法区中类静态属性引用的对象

    **方法区中常量引用的对象

    **本地方法栈中的JNI(即一般说的Native方法)

     

    (3)再谈引用

    前言:

     

    无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判断对象是否存活都与"引用"有关。

    2.3.1jdk1.2以前

     

    如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。

    2.3.2jdk1.2以后

    我们希望描述这样一类对象:内存空间足够,则保留在内存中;如果内存进行垃圾收集后还是非常紧张,则可以抛弃这些。很多系统的缓存功能都符合这样的场景。

    于是Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种。引用强度依次减弱

     

    强引用:就是指在程序代码中普遍存在的,类似"Object obj = new Object();"这类引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。

     

    软引用:用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行二次回收。如果这次回收还没有足够内存,才会抛出内存溢出异常。Jdk1.2后,提供了SoftReference类来实现软引用。

     

    弱引用:用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。垃圾收集器工作时,无论当前内存是否足够,都会回收掉弱引用关联的对象。JDK1.2后提供了WeakReference类来实现弱引用。

     

    虚引用:也称为幽灵引用或幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的内存,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。JDK1.2之后,提供了PhantomReference来实现。

     

    (4)生存还是死亡(Java中的finalize方法)

     

  • 相关阅读:
    sap快捷登录
    转载(略有修改):Windows 8的承载网络设置方法(w8 创建无线网络/ap)
    转载:Keytool 工具介绍
    minecraft初探
    linux图像界面连接-xdm
    经典的始终经典(牛蛙)
    vmware install win8 and server2012 problem
    windows硬盘优化篇
    网络15软工个人作业5——软件工程总结
    个人作业4——alpha阶段个人总结
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/9381002.html
Copyright © 2011-2022 走看看