多语言展示
当前在线:1185今日阅读:75今日分享:44

java中垃圾回收的方法

Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。      Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。      java的垃圾内存不需要程序代码来显式地释放,JVM在实现的时候都有一个由垃圾回收所管理的堆。垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。
工具/原料

电脑

方法/步骤
1

第一点:java垃圾回收机制。在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是'无用信息',这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。 垃圾收集能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。 垃圾收集的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象, 而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾收集算法的不完备性,早先采用的某些垃圾收集算法就不能保证100%收集到所有的废弃内存。当然随着垃圾收集算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。

2

第二点:检测垃圾算法。1、引用计数算法(Reference Counting)原理:给每个对象添加一引用计数器,每当有一个地方引用它,计数器+1 ,引用失效时就-1 。分析:引用计数算法很简单高效。但是,现在主流的虚拟机没有选用引用计数算法来管理内存,原因是它很难解决对象之间相互引用的问题。public class ReferenceCountingGC{    public Object instance = null;    public static void testGC(){        ReferenceCountingGC objA = new ReferenceCountingGC ();        ReferenceCountingGC objB = new ReferenceCountingGC ();        objB.instance = objA;        objA.instance = objB;        objA = null;        objB = null;        System.gc();    }}此处objA,objB 不会回收,因为其还有其它引用2、可达性分析算法(Rearchability Analysis)原理:以根集对象为起始点进行搜索,如果有对象不可达的话,即是垃圾对象。这里的根集一般包括java栈中引用的对象、方法区常良池中引用的对象、本地方法中引用的对象等。

3

第三点:对象的四种引用。强引用 :创建一个对象并把这个对象直接赋给一个变量,不管系统资源多么紧张,强引用的对象都不会被回收,即使他以后不会再用到。软引用 :通过SoftReference修饰的类,内存非常紧张的时候会被回收,其他时候不会被回收,在使用之前要判断是否为null从而判断他是否已经被回收了。弱引用 :通过WeakReference修饰的类,不管内存是否足够,系统垃圾回收时必定会回收。虚引用 :不能单独使用,主要是用于追踪对象被垃圾回收的状态。通过PhantomReference修饰和引用队列ReferenceQueue类联合使用实现。如下所示:分别是强,软,弱的测试,虚使用较少暂不介绍。

4

第四点:垃圾回收机制1、串行回收和并行回收:串行回收是不管系统有多少个CPU,始终只用一个CPU来执行垃圾回收操作;并行回收就是把整个回收工作拆分成多个部分,每个部分由一个CPU负责,从而让多个CPU并行回收。并行回收的执行效率很高,但更复杂,内存会增加。/2、程序停止和并发执行 :顾名思义是在执行垃圾回收的同时会导致应用程序的暂停。并发执行垃圾回收虽不会导致应用程序的暂停,但需要解决和应用程序的执行冲突,因此系统开销比较高,执行时需要更多的堆内存。3、标记不压缩:标记-清除要遍历两次。第一次先从根集开始访问所有可达对象,并将他们标记为可达状态。第二次遍历整个内存区域,对不达状态的对象进行回收处理。这种回收方式不压缩,不需要额外内存,但要两次遍历,会产生碎片。4、标记压缩 :所有的可达对象集合到一起,将之前占用的内存全部回收,减少内存碎片的产生。/5、复制式的垃圾回收:将堆内存分成两个相同空间,将空间A的可达对象全部复制到空间B,然后一次性回收A的空间。因为只需访问可达对象,复制走之后直接回收整个空间,完全不用理会不可达对象,所以遍历空间成本小效率高,但复制的空间成本大。典型的拿“空间”换“时间”。

5

第五点:堆内存的分代回收1、年轻世代采用复制式回收算法,划分两个区域,分别是E 区和 S 区。大多数对象先分配到Eden区,内存大的对象会直接被分配到老年代中。S 区又分Form、To两个小区,一个用来保存对象,另一个是空的;每次进行年轻代垃圾回收的时候,就把E大区和From小区中的可达对象都复制到To区域中,一些生存时间长的就直接复制到了老年代。最后,清理回收E大区和From小区的内存空间,原来的To空间变为From空间,原来的From空间变为To空间。2、年老世代 回收机制 :采用标记压缩算法回收。对象来源 :对象大直接进入老年代、Young代中生存时间长的可达对象。回收频率 :因为很少对象会死掉,所以执行频率不高,而且需要较长时间来完成。3、永久世代 用      途 :用来装载Class,方法等信息,默认为64M(Android的运行时应用分配的内存),不会被回收。对象来源 :像Hibernate,Spring这类喜欢AOP动态生成类的框架,往往会生成大量的动态代理类,因此我们经常遇到java.lang.OutOfMemoryError:PermGen space的错误,这就是Permanent代内存耗尽所导致的错误。回收频率 :不会被回收。

6

第六点:垃圾回收的方法1.对象被赋值null,或者手动释放User user = new User();user = null;或者System.gc();和Runtime.getRuntime().gc();等价2、弱引用如果一个对象具有弱引用,在GC线程扫描内存区域的过程中,不管当前内存空间足够与否,都会回收内存,使用弱引用 构建非敏感数据的缓存。弱引用申明:WeakReferenceweakReference=new WeakReference(new User());3、虚引用如果一个对象仅持有虚引用,在任何时候都可能被垃圾回收,虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列联合使用,虚引用主要用来跟踪对象 被垃圾回收的活动。虚引用申明:PhantomReference phantomReference=new PhantomReference(new User(),new ReferenceQueue());

7

小结 实际开发中常用的小技巧:1、尽量使用直接变量,例如:String javaStr = “XXX”;2、使用 StringBuilder 和 StringBuffer 进行字符串连接等操作;3、尽早释放无用对象;4、尽量少使用静态变量;5、缓存常用的对象:可以使用开源的开源缓存实现,例如:OSCache,Ehcache;6、尽量不使用 finalize() 方法;7、在必要的时候可以考虑使用软引用 SoftReference。

注意事项
1

就算显示的调用Java的垃圾回收GC,java也不会立刻回收垃圾。

2

当新对象生成,并且在Eden申请空间失败时,会触发年轻代的垃圾回收 当 年老代(Tenured)被写满 ,久代(Perm)被写满 ,System.gc()被显示调用般情况下,上一次GC之后Heap的各域分配策略动态变化,会触发full gc;

推荐信息