Android和Java的垃圾回收

来源:互联网 发布:php调用接口的方法 编辑:程序博客网 时间:2024/06/06 00:23

来讨论一下Android的GC操作,GC全称是Garbage Collection,也就是所谓的垃圾回收。Android系统会在适当的时机触发GC操作,一旦进行GC操作,就会将一些不再使用的对象进行回收。那么哪些对象会被认为是不再使用,并且可以被回收的呢?我们来看下面一张图:


上图当中,每个蓝色的圆圈就代表一个内存当中的对象,而圆圈之间的箭头就是它们的引用关系。这些对象有些是处于活动状态的,而有些就已经不再被使用了。那么GC操作会从一个叫作Roots的对象开始检查,所有它可以访问到的对象就说明还在使用当中,应该进行保留,而其它的对象就表示已经不再被使用了,如下图所示:


可以看到,目前所有黄色的对象仍然会被系统继续保留,而蓝色的对象就会在GC操作当中被系统回收掉了,这大概就是Android系统一次简单的GC流程。

优先级:前台,可见,服务,后台,empty

一般情况下一共有以下几种触发GC操作的原因:

  • GC_CONCURRENT:   当我们应用程序的堆内存快要满的时候,系统会自动触发GC操作来释放内存。
  • GC_FOR_MALLOC:   当我们的应用程序需要分配更多内存,可是现有内存已经不足的时候,系统会进行GC操作来释放内存。
  • GC_HPROF_DUMP_HEAP:   当生成HPROF文件的时候,系统会进行GC操作,关于HPROF文件我们下面会讲到。
  • GC_EXPLICIT:   这种情况就是我们刚才提到过的,主动通知系统去进行GC操作,比如调用System.gc()方法来通知系统。或者在DDMS中,通过工具按钮也是可以显式地告诉系统进行GC操作的。(不要大量使用)



Java垃圾回收:

数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因

当应用程序空闲时,即没有应用线程在运行时,GC会被调用,Java垃圾回收线程就是一个典型的守护线程, 当我们的程序中不再有任何运行中的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。 它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。

只有程序需要更多额外内存或应用程序空闲时垃圾回收机制才会进行垃圾回收;只有一个对象处于不可达状态,系统才会真正回收该对象所占有的资源(堆内存和方法区)

程序无法精确控制垃圾回收的运行(但我们可以通知系统进行垃圾回收,System.gc(),但系统是否进行垃圾回收仍然不确定),只负责回收堆内存的对象,回收任何对象之前会调用它的finalize()方法


对象的三种状态:

可达状态:有一个以上的变量引用一个对象

可恢复状态:不再有任何变量引用它,垃圾回收时系统会调用所有可恢复状态的对象的finalize()方法进行资源清理,如果重新有引用变量引用该对象会变为可达状态,否则进入不可达状态

不可达状态:没有变量引用,且finalize()方法也没使该对象变成可达状态,永久失去引用


对象的四种引用:

强引用:创建一个对象,赋给一个引用变量,处于可达状态,不可能被系统垃圾回收机制回收

软引用:垃圾回收机制运行时,系统内存空间足够不会被回收,不足够会被回收

弱引用:垃圾回收机制运行时,不管系统内存是否足够,都会被回收

虚引用:几乎等于没有引用,主要用于跟踪对象被垃圾回收的状态


gcRoots:

    1、(栈帧中的本地变量表)中引用的对象

    2、方法区中的静态成员。

    3、方法区中的常量引用的对象(全局变量)

    4、本地方法栈中JNI(一般说的Native方法)引用的对象。

 减少GC开销的措施

  根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:

  (1)不要显式调用System.gc()

  此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。

  (2)尽量减少临时对象的使用

  临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。

  (3)对象不用时最好显式置为Null

  一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。

  (4)尽量使用StringBuffer,而不用String来累加字符串

  由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。

  (5)能用基本类型如Int,Long,就不用Integer,Long对象

  基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。

  (6)尽量少用静态对象变量

  静态变量属于全局变量,不会被GC回收,它们会一直占用内存。

  (7)分散对象创建或删除的时间

  集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。




0 0
原创粉丝点击