总结Java垃圾回收器的方法和原理 篇一
垃圾回收(Garbage Collection,GC)是Java语言所提供的一种自动内存管理机制。通过垃圾回收器,Java程序能够自动地回收内存中不再使用的对象,从而避免了手动释放内存的繁琐工作,提高了程序的开发效率和性能。本文将总结Java垃圾回收器的方法和原理。
Java垃圾回收器的方法主要有两种:标记-清除法(Mark-Sweep)和复制算法(Copying)。
标记-清除法是最基本的垃圾回收算法之一。它的核心思想是通过标记所有活动对象,然后清除掉所有未标记的对象。具体流程如下:
1. 首先,垃圾回收器会从根对象(如程序的入口点、全局变量等)开始,遍历对象图,并标记所有可达的对象。
2. 然后,垃圾回收器会进行一次全局的扫描,清除所有未标记的对象,释放它们所占用的内存空间。
标记-清除法的优点是可以回收任意形状、任意大小的内存碎片,但其缺点也很明显:清除过程中会产生大量的内存碎片,降低了内存的利用率;同时,标记和清除的过程也会占用较长的时间。
为了解决标记-清除法的缺点,复制算法应运而生。复制算法将内存空间划分为两个相等的区域:From区和To区。垃圾回收器首先将所有存活的对象复制到To区,然后清除From区中的所有对象。具体流程如下:
1. 首先,垃圾回收器会从根对象开始,遍历对象图,并将所有活动对象复制到To区。
2. 然后,垃圾回收器会将所有指针指向From区的对象更新为To区的地址。
3. 最后,垃圾回收器会清除From区的所有对象,释放它们所占用的内存空间。
复制算法的优点是简单高效,不会产生内存碎片,但其缺点也很明显:需要额外的内存空间来存储复制的对象,浪费了一部分内存资源。
除了标记-清除法和复制算法,Java垃圾回收器还有其他一些优化方法和技术,如分代收集(Generational Collection)、增量收集(Incremental Collection)和并发收集(Concurrent Collection)等。这些方法和技术的目的都是为了提高垃圾回收的效率和性能。
总结Java垃圾回收器的原理,可以归纳为以下几点:
1. 标记-清除法和复制算法是Java垃圾回收器的两种基本方法,它们分别通过标记和清除、复制和清除的方式来回收内存中的垃圾对象。
2. 标记-清除法能够回收任意形状、任意大小的内存碎片,但会产生大量的内存碎片,降低了内存的利用率。
3. 复制算法可以高效地回收内存碎片,但需要额外的内存空间来存储复制的对象,浪费了一部分内存资源。
4. Java垃圾回收器还可以通过分代收集、增量收集和并发收集等优化方法和技术来提高回收效率和性能。
综上所述,了解Java垃圾回收器的方法和原理对于开发高效且稳定的Java程序非常重要。开发人员可以根据具体的应用场景选择合适的垃圾回收器,并结合优化方法和技术来提高垃圾回收的效率和性能。
总结Java垃圾回收器的方法和原理 篇三
一、认识Java的自动垃圾回收
垃圾回收是Java语言的一大特性,方便了编程,是以消耗性能为代价的。而垃圾在这里只无用的对象。而C++是需要程序员自己写析构函数来释放内存的,麻烦,也有可能忘记而导致内存泄露。
Java语言对内存的分配管理是通过JVM内部机制决定的。程序员可以不关心其处理。
二、垃圾回收的原理和意义
Java虚拟机中有个称之为垃圾回收器的东西,实际上这个东西也许真正不存在,或者是已经集成到JVM中了,但这无关紧要,我们仍然可以称为为垃圾回收器。
垃圾回收器的作用是查找和回收(清理)无用的对象。以便让JVM更有效的使用内存。
垃圾回收器的运行时间是不确定的,由JVM决定,在运行时是间歇执行的。虽然可以通过System.gc()来强制回收垃圾,但是这个命令下达后无法保证JVM会立即响应执行,但经验表明,下达命令后,会在短期内执行你的请求。JVM通常会感到内存紧缺时候去执行垃圾回收操作。
垃圾回收过于频繁会导致性能下降,过于稀疏会导致内存紧缺。这个JVM会将其控制到最好,不用程序员担心。但有些程序在短期会吃掉大量内存,而这些恐怖的对象很快使用结束了,这时候也许有必要强制下达一条垃圾回命令,这是很有必要的,以便有更多可用的物理内存。
从上面了解到,没有用的对象就是垃圾。准确的说,当没有任何线程访问一个对象时,该对象就符合垃圾回收的条件。
对于String,存在一个字符串池,这个不属于本文讨论的范围,字符串池中的垃圾回收,算法和这里所讨论的垃圾回收完全是两码事。但是不得不说的是,字符串的胡乱拼接,往往导致性能急剧下降,尤其是在庞大的循环语句中,拼接字符串就是在让程序慢性自杀。这也是很多Java程序员容易犯的毛病。
字符串既然是池,就是为了缓冲,为了有更高的命中率,因此垃圾回收的频率也许会比JVM对象垃圾回收器要低很多。
垃圾回收器仅仅能做的是尽可能保证可用内存的使用效率,让可用内存得到高效的管理。程序员可以影响垃圾回收的执行,但不能控制。
三、通过编程影响垃圾回收
虽然程序员无法控制JVM的垃圾回收机制。但是可以通过编程的手段来影响,影响的方法是,让对象符合垃圾回收条件。
分别说来有一下几种:
1、将无用对象赋值为null.
2、重新为引用变量赋值。比如:
Person p = new Person("aaa");
p = new Person("bbb");
这样,new Person("aaa")这个对象就是垃圾了——符合垃圾回收条件了。
3、让相互联系的对象称为“岛”对象
Person p1 = new Person("aaa");
Person p2 = new Person("bbb");
Person p3 = new Person("ccc");
p1=p2; p2=p3; p3=p1;
p1=null; p2=null; p3=null;
在没有对p1、p2、p3置null之前,它们之间是一种三角恋关系。分别置null,三角恋关系依然存在,但是三个变量不在使用它们了。三个Person对象就组成了一个孤岛,最后死在堆上——被垃圾回收掉。
4、强制的垃圾回收System.gc()
实际上这里的强制,是程序员的意愿、建议,什么时候执行是JVM的垃圾回收器说了算。
调用垃圾回收也不一定能保证未使用的对象一定能从内存中删除。
唯一能保证的是,当你内存在极少的情况,垃圾回收器在程序抛出OutofMemaryException之前运行一次。
总结Java垃圾回收器的方法和原理 篇四
Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation)、自动回收(Garbage Collect)功能,这两个操作都发生在Java堆上(一段内存快)。某一个时点,一个对象如果有一个以上的引用(Rreference)指向它,那么该对象就为活着的(Live),否则死亡(Dead),视为垃圾,可被垃圾回收器回收再利用。垃圾回收操作需要消耗CPU、线程、时间等资源,所以容易理解的是垃圾回收操作不是实时的发生(对象死亡马上释放),当内存消耗完或者是达到某一个指标(Threshold,使用内存占总内存的比列,比如0.75)时,触发垃圾回收操作。有一个对象死亡的例外,java.lang.Thread类型的对象即使没有引用,只要线程还在运行,就不会被回收。
回收的机制
依据统计分析可知,Java(包括一些其它高级语言)里面大多数对象生命周期都是短暂的,所以把Java内存分代管理。分代的目的无非就是为不同代的内存块运用不同的'管理策略(算法),从而最大化性能。相对于年老代,通常年轻代要小很多,回收的频率高,速度快。年老代则回收频率低,耗时长。内存在年轻代里面分配,年轻代里面的对象经过多个回收周期依然存活的会自动晋升到年老代。
设计选型(Design Choices)
设计选型影响JVM垃圾回收器的实现难度,以及JVM的性能指标,适用于不同的场景。描述的是回收算法的风格特点。
单线程串行回收 VS 多线程并行回收
回收操作自身是否多线程处理的问题。单线程回收的优点是简单,易实现,碎片少,适用于单核的机器。多线程并行回收在多核机器上面可以充分的利用CPU资源,减少回收的时间,增加生产力,缺点是复杂且可能有部分碎片没有回收。
回收时暂停应用线程 VS 回收和应用并发进行
回收操作时是否暂停应用线程的问题。暂停应用线程的优点是简单、准确、清理得比较干净、清理的时间也短(CPU资源独占),缺点是暂停应用线程之后会造成垃圾回收周期内应用的回应时间拉长,实时性非常高的系统比较敏感。回收和应用线程并行处理的优点是应用反应时间比较平稳、缺点是实现难度大、清理频率高、可能有碎片。
不合并释放的内存片段 VS 合并释放的内存片段 VS 把活着的复制到新的地方
这三个选型描述的是如何管理死亡的内存块片段。死亡的内存片段通常散落在堆的各个地方,如果不加以管理会有两个问题,内存分配的时候因查找可用的内存而导致速度慢,小的碎片会导致内存的浪费(比如大的数组要求大的连续内存片段)。管理有两种方式,把活着的内存挪到内存块的某一端,记录可用内存的开始位置,或者干脆把活着的内存复制到一个新的内存区域,原来的内存块整个空出来。
性能指标(Performance Metrics)
①生产率(Throughput)
一个较长的周期(长的周期才有意义)内,非回收时间占总时间的比率。度量系统的运行效率。
②垃圾回收花费(Garbage Collection overhead)
一个较长的周期内,回收时间占总时间的比率。与生产率相对应,加起来为100%。
③暂停时间间隔(Pause time)
Java虚拟机在回收垃圾的时候,有的算法会暂停所有应用线程的执行,某些系统可能对暂停的时间间隔比较敏感。
④回收的频率(Frequency of collection)
平均多久会发生回收操作。
⑤内存占用的大小(Footprint)
如堆的大小。
⑥、实时性(Promptness)
自一个对象死亡起,经过多久该对象所占用内存被回收。
垃圾回收的类型
所有的回收器类型都是基于分代技术。Java HotSpot虚拟机包含三代,年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation)。
①永久代
存储类、方法以及它们的描述信息。可以通过-XX:PermSize=64m和-XX:MaxPermSize=128m两个可选项指定初始大小和最大值。通常 我们不需要调节该参数,默认的永久代大
小足够了,不过如果加载的类非常多,不够用了,调节最大值即可。
②年老代
主要存储年轻代中经过多个回收周期仍然存活从而升级的对象,当然对于一些大的内存分配,可能也直接分配到永久代(一个极端的例子是年轻代根本就存不下)。
③年轻代
绝大多数的内存分配回收动作都发生在年轻代。如下图所示, 年轻代被划分为三个区域,原始区(Eden)和两个小的存活区(Survivor),两个存活区按功能分为From和To。绝大多数的对象都在原始区分配,超过一个垃圾回收操作仍然存活的对象放到存活区。
串行回收器(Serial Collector)
单线程执行回收操作,回收期间暂停所有应用线程的执行,client模式下的默认回收器,通过-XX:+UseSerialGC命令行可选项强制指定。