zoukankan      html  css  js  c++  java
  • 谈JAVA的内存回收(一)

    JAVA的内存回收

    程序员需要通过关键字new创建Java对象,即可视为Java对象申请内存空间,JVM会在堆内存中为每个对象分配空间,当一个Java对象失去引用时,JVM的垃圾回收机制会自动清除他们,并回收它们所占用的内存空间。Java内存管理包括内存分配(创建Java对象时)和内存回收(回收Java对象)两个方面。这两方面工作都是由JVM自动完成的。

    Java对象被创建之后,垃圾回收机制会实时地监控每一个对象的运行状态,包括对象的申请,引用,被引用,赋值等。当垃圾回收机制实时地监控某个对象不再被引用变量所引用时,立即回收机制就会回收它所占用的空间。基本上,可以把JVM内存中对象引用理解成一种有向图,把引用变量,对象都当成为有向图的顶点,将引用关系当成图的有向边,有向边总是从引用端指向被引用的Java对象。因为Java所有对象都是由一条一条线程创建出来的,因此可把线程对象当成有向图的起始顶点。对于单线程而言,整个程序只有一条main线程,那么该图就是以main进程为顶点的有向图。在这个有向图中,main顶点可达的对象可达状态,垃圾回收机制不会回收它们;如果某个对象在这个有向图中处于不可达状态,那么就认为这个对象不再被引用,接下来垃圾回收机制就会主动回收它了。

    class Node{

          Node next;

          String name;

          public Node(String name){

                this.name = name;

          }

    }

    publicclass NodeTest {

        publicstaticvoid main(String[] args){

          Node n1 = new Node("The first node");

          Node n2 = new Node("The second node");

          Node n3 = new Node("The third node");

          n1.next = n2;

          n2 = null;

          n3 = n2;

        }

    }

    main开始,有一条路径可带“The first node“,因此该对象处于可达状态,垃圾回收机制不会回收它;从main顶点开始,有两条路径可达”The second node”,因此该对象处于可达状态,垃圾回收机制也不会回收它;从main顶点开始,没有路径可以到达”The third node”,因此这个Java对象就变成了垃圾,接下来垃圾回收机制就会开始回收它。

    采用有向图来管理内存中的对象具有高的精度,但是缺点是效率较低。

    当一个对象在堆内存中运行时,根据它在对应有向图中的状态,可以把它所处的状态分成如下3种:

    1. 可达状态:当一个对象被创建后,有一个以上的引用变量引用它。在有向图中可从起始顶点到该对象,那它就处于可达状态,程序可通过引用变量来调用该对象的属性和方法。
    2. 可恢复状态:如果程序中某个对象不再有任何引用变量引用它,它将先进入可恢复状态,此时从有向图的起始顶点不能到达该对象。在这个状态下,系统的垃圾回收机制准备回收该对象所占用的内存。在回收该对象之前,系统会调用可恢复状态的对象的finalize方法进行资源清理,如果系统在调用finalize方法重新让一个以上引用变量引用该对象,则这个对象会再次变为可达状态;否则,该对象将进入不可达状态。
    3. 不可达状态:当对象的所有关联都被切断,且系统被调用所有对象的finalize方法依然没有使该对象变成可达状态,那这个对象将永久性地失去引用,最后变成不可达状态。只有当一个对象处于不可达状态时,系统才会真正回收该状态所占有的资源。

     

    publicclass StatusTranfer {

        publicstaticvoid test(){

          String a = new String("aaa");

          a = new String("bbb");

        }

        publicstaticvoid main(String[] args){

          test();

        }

    }

    当程序执行test方法的代码时,代码定义了一个a变量,并指向字符串”aaa”,字符串”aaa”处于可达状态,当执行完”bbb”后,“aaa“处于可恢复状态,”bbb”指向可达状态。

    一个对象可以被一个方法局部变量所引用,也可以被其他类的类变量引用,或者被其他对象的实例变量性引用。当某个对象被其他类的类变量引用时,只有该类被销毁后,该对象才会进入可恢复状态;当某个对象被其他对象的实例变量引用时,只有当引用该变量的对象被销毁或变成不可达状态后,该对象才会进入不可达状态。

    为了更好地管理对象的个,从JDK1.2开始,Javajava.lang.ref包下提供了3个类:SoftReference,PhantomReferenceWeakReference.

    程序创建一个对象,并把这个对象赋给一个引用变量,这个引用变量就是强引用。

    Java程序可通过强引用来访问实际的对象,当一个对象被一个或多个强引用变量所引用时,它处于可达状态,它不可能被系统垃圾回收机制回收,即使是内存非常紧张的时候。因此它容易造成内存泄露。

    软引用需要通过SoftReference类来实现,当一个对象只具有软引用时,它很可能被垃圾回收机制回收。对于只有软引用的对象而言,当系统内存空间足够时,不会被系统回收。

    当程序需要大量创建某个类的新对象,而且有可能重新访问已创建来对象时可以充分使用软引用来解决内存紧张的难题。

    例如,需要访问1000Person对象,可以有两种方式:

    1. 一次创建1000Person对象,但只有一个Person引用指向最后一个Person对象;
    2. 定义一个长度为1000Person数组,每个数组元素引用一个Person对象。

    第一种情况,程序不允许需要重新访问前面创建的对象,即使这个对象所占的堆空间还没有被回收。但已经失去了这个对象的引用,因此也不得不重新创建一个新的Person对象(重新分配内存)。而那个已有的Person对象则是等待被回收。

    第二种情况,优势是可以随时重新访问前面创建的每个Person对象。弱点是如果系统堆内存空间紧张,而1000Person对象都被强引用引用着,垃圾回收机制也不可能回收它们的堆内存空间,系统性能差。

    如果使用软引用则是比较好的方案。如下:

    import java.lang.ref.SoftReference;

    class Person{

          String name;

          intage;

          public Person(String name,int age){

                this.name = name;

                this.age = age;

          }

          public String toString(){

                return"Person[name="+name+",age="+age+"]";

          }

    }

    publicclass SoftReferenceTest {

        publicstaticvoid main(String[] args){

          SoftReference<Person>[] people = new SoftReference[10000000];

          for(int i=0;i<people.length;i++){

                people[i] = new SoftReference<Person>(new Person("name"+i,(i+1)*4%100));

          }

          System.out.println(people[2].get());

          System.out.println(people[4].get());

          System.gc();

          System.runFinalization();

          System.out.println(people[2].get());

          System.out.println(people[4].get());

        }

    }

    Output:

     

     

     

  • 相关阅读:
    从搜索引擎角度看SEO
    关键词排名与网站优化有哪三大误区?
    真正提升关键词排名的外链应该怎样发?
    高质量外链的十大特性
    四个方面分析SEO如何提高网站的权重
    Linux(ubuntu)使用dd从iso制作win7安装u盘(读卡器一样),以及备份分区
    折腾slidingmenu
    生命游戏介绍
    21232f297a57a5a743894a0e4a801fc3
    final关键字
  • 原文地址:https://www.cnblogs.com/riskyer/p/3231047.html
Copyright © 2011-2022 走看看