一、相关概念
基本回收算法
- 引用计数( Reference Counting )
比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃 圾回收时,只用收集计数为 0 的对象。 此算法最致命的是无法处理循环引用的问题。 - 标记 - 清除( Mark-Sweep )
此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整 个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。 - 复制( Copying )
此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把 正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内 存整理,不过出现 " 碎片 " 问题。当然,此算法的缺点也是很明显的,就是需要两 倍内存空间。 - 标记 - 整理( Mark-Compact )
此算法结合了 " 标 记 - 清除 " 和 " 复制 " 两个算法的优点。也是分两阶段,第一阶段从根节点开始 标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 " 压缩 " 到堆 的其中一块,按顺序排放。此算法避免了 " 标 记 - 清除 " 的碎片问题,同时也避免了 " 复制 " 算法的空间问题。 - 增量收集( Incremental Collecting )
实施垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么原因 JDK5.0 中的收集器没有使用这种算法的。 - 分代( Generational Collecting )
基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对 不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从 J2SE1.2 开始)都是使用此算法的。
分代垃圾回收详述
如上图所示,为 Java 堆 中的各代分布。
- Young (年轻代)
年轻代分三个区。一个 Eden 区,两个 Survivor 区。大部分对象在 Eden 区中生成。当 Eden 区满时,还存活的对象将被复制到 Survivor 区(两个中的一个),当这个 Survivor 区满时,此区的存活对象将被复制到另 外一个Survivor 区,当这个 Survivor 去也满了的时候,从第一个 Survivor 区复制过来的并且此时还存活的对象, 将被复制" 年老区 (Tenured)" 。需要注意, Survivor 的两个区是对称的,没先后关系,所以 同一个区中可能同时存在从Eden 复制 过来 对象,和从前一个 Survivor 复 制过来的对象,而复制到年老区的只有从第一个 Survivor 去 过来的对象。而且, Survivor 区 总有一个是空的。 - Tenured (年 老代)
年老 代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。 - Perm (持 久代)
用于 存放静态文件,如今 Java 类、方法 等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class ,例如 Hibernate 等,在这种时候需要设置一 个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过 -XX:MaxPermSize= 进行设置。
GC 类型
GC 有 两种类型: Scavenge GC 和 Full GC 。
- Scavenge GC
一般情 况下,当新对象生成,并且在 Eden 申 请空间失败时,就好触发 Scavenge GC , 堆 Eden 区域进行 GC,清除非存活对象,并且把尚且存活的对象移动到 Survivor 区。然后整理 Survivor 的两个区。 -
Full GC
对整个堆进行整 理,包括 Young 、 Tenured 和 Perm 。 Full GC 比 Scavenge GC 要慢,因此应该尽可能减少Full GC 。有如下原因可能导致 Full GC :- Tenured 被写满
- Perm 域被写满
- System.gc() 被显示调用
- 上一次 GC 之 后 Heap 的各域分配策略动态变化
分代垃圾回收过程演示
二、垃圾回收器
目前的收集器主要有三种:串行收集器、并行收集器、并发收集器 。
- 串行收集器
使 用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机 器。当然,此收集器也可以用在小数据量( 100M 左 右)情况下的多处理器机器上。可以使用 -XX:+UseSerialGC 打 开。 -
并行收集器
- 对年轻代进行并行垃圾回收,因此可以减少垃圾回收时间。一般在多线程多处理 器机器上使用。使用 -XX:+UseParallelGC. 打 开。并行收集器在 J2SE5.0 第 六 6 更新上引入,在 Java SE6.0 中进行了增强 -- 可以堆年老代进行并行收集。如果年老代不使用并发收 集的话,是使用单线程进行垃圾回收,因此会制约扩展能力。使用 -XX:+UseParallelOldGC 打开。
- 使用 -XX:ParallelGCThreads= 设置并行垃圾回收的线程数。此值可以设置与机器处理 器数量相等。
-
此收集器可以进行如下配置:
- 最大垃圾回收暂停 : 指定垃圾回收时的最长暂停时间,通过 -XX:MaxGCPauseMillis= 指定。为毫秒 . 如果指定了此值的话,堆大小和垃圾回收相关参数会进行 调整以达到指定值。设定此值可能会减少应用的吞吐量。
- 吞吐量 : 吞吐量为垃圾回收时间与非垃圾回收时间的比值,通过 -XX:GCTimeRatio= 来设定,公式为 1/ ( 1+N )。例如, -XX:GCTimeRatio=19 时,表示 5% 的时间用于垃圾回收。默认情况为 99 ,即 1% 的时间用于垃圾回收。
-
并发收集器
可以保证大部分工作都并发进行(应用不 停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用。使用 -XX:+UseConcMarkSweepGC 打 开。
- 并 发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,跟踪可达对象。在每个年老代垃圾回收周期中,在 收集初期并发收集器会 对整个应用进行简短的暂停,在收集中还会再暂停一次。第二次暂停会比第一次稍长,在此过程中多个线程同时进行垃圾回收工作。
- 并发收集器使用处理器换来短暂的停顿时间。在一个 N 个处理器的系统上,并发收集部分使用 K/N个可用处理器进行回收,一般情况下 1<=K<=N/4 。
- 在只有一个处理器的主机上使用并发收集器,设置为 incremental mode 模式也可获得较短的停 顿时间。
- 浮动垃圾 :由于在应用运行的同时进行垃圾回收,所以有些 垃圾可能在垃圾回收进行完成时产生,这样就造成了 "Floating Garbage" ,这些垃圾需要在下次垃圾回收周期时才能回收掉。所以,并发收集器一般需要20% 的预留空间用于这些浮 动垃圾。
- Concurrent Mode Failure :并发收集器在应用运行时进行收集,所以需要保证堆在垃圾回收的这段时 间有足够的空间供程序使用,否则,垃圾回收还未完成,堆空间先满了。这种情况下将会发生 " 并发模式失败" ,此时整个应用将会暂停,进行垃圾回收。
- 启动并发收集器 :因为并发收集在应用运行时进行收集,所 以必须保证收集完成之前有足够的内存空间供程序使用,否则会出现 "Concurrent Mode Failure" 。通过设置 -XX:CMSInitiatingOccupancyFraction=指 定还有多少剩余堆时开始执行并发收集
-
小结
- 串行处理器:
-- 适用情况:数据量比较小( 100M 左右);单处理器下并且对响应时间无要求的应用。
-- 缺点:只能用于小型应用 - 并行处理器:
-- 适用情况: " 对 吞吐量有高要求 " ,多 CPU 、对应用响应时间无要求的中、大型应用。举例: 后台处理、科学计算。
-- 缺点:应用响应时间可能较长 - 并发处理器:
-- 适用情况: " 对 响应时间有高要求 " ,多 CPU 、对应用响应时间有较高要求的中、大型应用。举 例: Web 服务器 / 应用服务器、电信交换、集成开发环境。
- 串行处理器:
三、常见配置举例
-
堆大小设置
JVM 中最大堆大小 有三方面限制:相关操作系统的数据模型( 32-bt 还 是 64-bit )限制;系统的可用虚拟 内存限制;系统的可用物理内存限制。 32 位 系统下,一般限制在 1.5G~2G ; 64 为操作系统对内存无限制。我在Windows Server 2003 系统, 3.5G 物理内存, JDK5.0 下测试,最大可设置为 1478m 。
典型设置:- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-Xmx3550m :设置 JVM 最 大可用内存为 3550M 。
-Xms3550m :设置 JVM 促 使内存为 3550m 。此 值可以设置与 -Xmx 相 同,以避免每次垃圾回收完成后 JVM 重新 分配内存。
-Xmn2g :设置年轻代大小为 2G 。 整 个堆大小 = 年轻代大小 + 年老代大小 + 持久代大小 。持久代一般固定大小为 64m ,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun 官方推荐配置为整个堆的 3/8 。
-Xss128k :设置每个线程的堆栈大小。 JDK5.0 以后每个 线程堆栈大小为 1M ,以前每个线程堆栈大小为 256K 。更 具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制 的,不能无限生成,经验值在3000~5000 左右。 - java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-XX:NewRatio=4: 设置年轻代(包括 Eden 和两个 Survivor 区)与年老代的比值(除去持久代)。设置为 4 ,则年轻代与年老代所占比值为 1 : 4 ,年轻代占整个堆栈的 1/5
-XX:SurvivorRatio=4 :设置年轻代中 Eden 区与 Survivor 区 的大小比值。设置为 4 ,则两个Survivor 区与一个 Eden 区的比值为 2:4 ,一个 Survivor 区占整个年轻代的 1/6
-XX:MaxPermSize=16m : 设 置持久代大小为 16m 。
-XX:MaxTenuringThreshold=0 :设 置垃圾最大年龄。 如果设置为 0 的话,则年轻代对象不经过Survivor 区,直接进入年老代 。对于年老代比较多的应用,可以提高效率。 如果将此值设置为一个较大值,则年轻代对象会在 Survivor 区进行多次复制,这 样可以增加对象再年轻代的存活时间,增加 在年轻代即被回收的概论。
- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-
回收器选择
JVM 给了三种选择:串行收集器、并行收集器、并发收集器 ,但 是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下, JDK5.0 以前都是使用串行收集器,如果想 使用其他收集器需要在启动时加入相应参数。 JDK5.0 以后, JVM 会根据当前 系统配置 进行判断。-
- java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
-XX:+UseParallelGC :选择垃圾收集器为并行收集器。 此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收 集。
-XX:ParallelGCThreads=20 :配 置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
-XX:+UseParallelOldGC :配置年老代垃圾收集方式为并行收集。 JDK6.0 支 持对年老代并行收集。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=100: 设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM 会 自动调整年轻代大小,以满足此值。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
-XX:+UseAdaptiveSizePolicy :设置此选项后,并行收集器会自动选择年轻代区大小和相应的 Survivor 区比例,以达到目标系统规 定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
- java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
-
- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+UseConcMarkSweepGC :设 置年老代为并发收集。测试中配置这个以后, -XX:NewRatio=4 的 配置失效了,原因不明。所以,此时年轻代大小最好用 -Xmn 设置。
-XX:+UseParNewGC: 设置年轻代为并行收集。可与 CMS 收集同时使用。 JDK5.0 以上,JVM 会根据系统配置自行设置,所以无需再 设置此值。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction : 由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生 " 碎片 " ,使得运行效率降低。此值设置运行多少次 GC 以后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection :打 开对年老代的压缩。可能会影响性能,但是可以消除碎片
- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-
-
- -XX:+PrintGC
输出形式: [GC 118250K->113543K(130112K), 0.0094143 secs]
[Full GC 121376K->10414K(130112K), 0.0650971 secs] - -XX:+PrintGCDetails
输 出形式: [GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs] - -XX:+PrintGCTimeStamps -XX:+PrintGC : PrintGCTimeStamps 可与上面两个混合 使用
输出形式: 11.851: [GC 98328K->93620K(130112K), 0.0082960 secs] - -XX:+PrintGCApplicationConcurrentTime: 打 印每次垃圾回收前,程序未中断的执行时间。可与上面混合使用
输出形式: Application time: 0.5291524 seconds - -XX:+PrintGCApplicationStoppedTime :打 印垃圾回收期间程序暂停的时间。可与上面混合使用
输出形式: Total time for which application threads were stopped: 0.0468229 seconds - -XX:+PrintHeapAtGC: 打 印 GC 前后的详细堆栈信息
输出形式:
34.702: [GC {Heap before gc invocations=7:
def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)
to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000)
tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
}
, 0.0757599 secs] - -Xloggc:filename: 与 上面几个配合使用,把相关日志信息记录到文件以便分析。
- -XX:+PrintGC
-
- Java 理论与实践 : 垃圾收集简史
- Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
- Improving Java Application Performance and Scalability by Reducing Garbage Collection Times and Sizing Memory Using JDK 1.4.1
- Hotspot memory management whitepaper
- Java Tuning White Paper
- Diagnosing a Garbage Collection problem
- Java HotSpot VM Options
- A Collection of JVM Options
- Frequently Asked Questions about Garbage Collection in the HotspotTM JavaTM Virtual Machine
相关推荐
老生常谈Java虚拟机垃圾回收机制 在Java虚拟机中,对象和数组的内存都是在堆中分配的,垃圾收集器主要回收的内存就是在堆内存中。如果在Java程序运行过程中,动态创建的对象或者数组没有及时得到回收,持续积累,...
JVM虚拟机垃圾回收机制图谱说明
Java垃圾回收机制是Java虚拟机(JVM)中的一种机制,用于防止内存泄露和有效地使用空闲的内存。垃圾回收机制的主要目的是为了回收无用的对象占用的内存空间,使该空间可被程序再次使用。 垃圾回收机制的算法有多种...
Java虚拟机(JVM)的垃圾回收(Garbage Collection,简称GC)机制是Java编程中的一个重要组成部分,它自动管理程序的内存,确保无用的对象能够被有效地释放,从而避免内存泄漏。本文将深入探讨Java垃圾回收的基本...
其中,垃圾回收机制(Garbage Collection, GC)是Java虚拟机(JVM)的一项重要特性,它能够自动检测并回收不再使用的对象占用的内存空间,从而有效避免了内存泄漏问题。本文将详细介绍Java中的垃圾回收机制及其工作原理...
总的来说,理解Java虚拟机的垃圾回收机制对于编写高效、健壮的Java程序至关重要。开发人员应避免过度依赖`finalize()`,而是利用更可靠的资源管理策略,如使用`try-with-resources`语句和合适的引用类型。同时,理解...
4.垃圾回收:Java虚拟机的垃圾回收机制可以自动回收不再使用的对象,避免内存溢出。 Java虚拟机的优点包括: * 平台无关性:Java虚拟机使得Java语言编译器生成的目标代码可以在多种平台上运行。 * 可移植性:Java...
在本文中,我们将深入探讨Java虚拟机的体系结构、垃圾回收机制、Java对象的生命周期和分代,以及相关的参数设置与调优。 Java虚拟机体系结构 Java虚拟机由三个主要组件组成:类加载器、运行时数据区和执行引擎。类...
本文将介绍Java虚拟机的使用和优化,包括Java虚拟机的特性、垃圾回收机制、性能优化方法等。 Java虚拟机的特性 Java虚拟机是Java语言的核心组件之一,它负责将Java源代码编译成字节码,并在不同的平台上解释执行...
垃圾回收机制是Java语言与生俱来的特性之一,与C/C++等语言相比,Java的内存管理更简单、更安全。 Java虚拟机规范还定义了类加载机制,即在JVM启动时或运行过程中动态加载类到内存中。类加载器在运行Java程序时按需...
### 垃圾回收机制详解 #### 一、引言 在现代软件开发中,内存管理一直是程序设计中的一项重要任务。特别是在高级编程语言中,如何有效地管理和释放内存资源成为了衡量一个程序性能的关键因素之一。Java作为一种...
### Java与C#的垃圾回收机制 #### 一、引言 在现代编程语言中,内存管理是一项重要的功能,能够显著提升程序的稳定性和效率。本文将深入对比Java与C#这两种广泛使用的编程语言中的垃圾回收机制,帮助开发者更好地...
### 基于实时性的Java虚拟机垃圾收集算法:深入解析与优化 #### 引言 垃圾收集(Garbage Collection, GC)是Java语言的重要特性之一,它通过自动化管理内存,减轻了程序员处理内存分配与释放的负担,提高了代码的...
Java的垃圾回收机制(Garbage Collection,GC)是Java虚拟机(JVM)的一个重要组成部分,它负责自动管理内存的分配和释放,以减轻程序员在内存管理方面的负担,并防止内存泄漏和内存溢出等问题。本文将详细探讨GC的...
而在Java中,这种内存管理的工作由Java虚拟机(JVM)内置的垃圾回收机制自动完成,极大地简化了程序员的工作。 垃圾收集的基本原理在于识别并自动回收那些不再被任何引用指向的对象所占用的内存空间。当一个对象...
Java垃圾回收机制是Java虚拟机(JVM)中的一种机制,用于释放垃圾占用的空间,以便提高系统性能和避免内存泄露。在Java中,垃圾回收机制主要解决两个问题:如何确定某个对象是“垃圾”?采用什么样的策略来进行回收...
Java的垃圾回收机制是Java虚拟机(JVM)的核心特性之一,它负责自动管理应用程序的内存,特别是对象的生命周期。垃圾回收的主要目标是回收不再被程序引用的对象所占用的内存,以便这部分空间可以被重新利用。 垃圾...