Garbage Collection 译为垃圾收集器(以下简称GC),主要负责内存分配、确保所有被引用的对象保留在内存中、将那些无法达到的对象引用所占用的内存回收。被引用的对象通常被称为活动的(live)。不再被引用的对象,认为是已经消亡,被称之为垃圾。寻找与释放对象占用空间的过程被称为垃圾收集/回收。
在Java 中是使用根搜索算法(GC Roots Tracing)判定对象是否存活。这个算法的基本思路就是通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots 没有任何引用链相连时,如图:
出现图中此种情况则证明此对象是“无法达到”不再可用。
在Java 中,可作为GC Roots 的对象包括下面几种:
- 虚拟机栈(栈帧中的局部变量表)中的引用的对象。
- 方法区中的类静态属性引用的对象。
- 方法区中的常量引用的对象。
- 本地方法栈中JNI(即一般说的Native 方法)的引用的对象。
说起垃圾收集,大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史远远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还未出生时,人们就已经在思考GC需要完成的三件事情:
哪些内存需要回收?
什么时候回收?
如何回收?
这三点也是我们想要寻求的答案,内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java 和C 之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM 来管理对象内存的分配以及对象内存的回收(GC)。
GC 其实是一种动态存储管理技术。主要是按照特定的垃圾收集算法(Garbage Collection Algorithm 简称GC算法)来实现自动资源回收的功能。简单地讲,就是将那些程序中显式释放内存的代码交由GC 在后台自动完成,能提供这种功能的编程语言,我们就说它支持GC,比如典型的Java、C#、Python 等,本文主要讨论HotSpot 系列Java 虚拟机中的GC。
高级编程语言采用GC 模式,省去了程序员自己管理内存的麻烦和危险。操作内存空间其实是极其危险的,稍有不慎可能导致内存泄漏(memory leak)或者悬空指针(dangling pointer)甚至整个系统崩溃。因此GC 的使用也一定程度上提升了系统的安全与稳定。
下图就描述了一个理想中系统模型,图中随着处理器的增加,GC花费时间不变的情况下所损失的吞吐量(可以简单的理解程序实际工作时间)。
当只花费1%时间去处理垃圾时,在32个处理器环境下最终损失了20%多的吞吐量,也就是说程序处理能力下降了20%多。
随着在GC 上花费时间越来越多,程序损失的吞吐量也在呈抛物线迅速上涨。当花费30%时间在GC 上时,程序几乎已经瘫痪,已经失去了运行的意义。
由此可见,在开发小型程序时我们往往可以不去关注GC 方面的优化及处理,但一旦系统规模庞大后,你就再也无法忽视这方面性能上的差异,几处微不足道的改良可能会获得性能大幅提升,所以无论在任何系统开发中都应该着重关注GC 方面的问题。
GC 的设计选择:
(1)串行回收(Serial)VS并行回收(Parallel)
串行就是不管有多少个CPU,始终只有一个CPU用来执行回收操作,而并行就是把整个回收工作拆分成多个,由多个CPU同时执行。并行回收执行会快,但复杂度增加,另外也有其他一些副作用,比如内存碎片会增加。
(2)并发执行(Concurrent)VS应用程序停止(Stop-the-world)
Stop-the-world的GC方式在执行GC的同时会导致应用程序的暂停。并发执行的GC虽然不会导致应用程序的暂停,但由于并发执行GC要解决和应用程序的执行冲突(应用程序可能会在GC的过称中修改对象),并发执行GC执行的消耗会高于Stop-the-world,而且执行也需要更多的内存堆。
(3)压缩(Compacting)VS不压缩(Non-compacting)VS拷贝(Copying)
为了减少内存碎片,支持压缩的GC会把所有的活对象搬迁到一起,然后将之前占用的内存全部回收。不压缩式的GC顾名思义就是在GC的过程中不压缩内存,较之压缩式的GC,不压缩式的GC回收内存快了,而分配内存慢了,而且无法解决内存碎片的问题。拷贝式的GC会将活对象拷贝到不同的内存区域中,这种方式的优点是源数据可以被认为已经清空并可以用来分配,缺点也很明显,需要拷贝数据和额外的内存。
GC 几种重要的性能指标:
(1)Throughput:经过长期运行后除去GC 处理时间系统实际执行时间所占全部时间的百分比。
(2)Garbage collection overhead:GC 开销,吞吐量的倒数,也就是说,在垃圾收集上花费的总时间的百分比。
(3)Pause time:程序执行期间暂停的时间,程序暂停后GC 开始工作,即前面说的stop-the-world 时间。
(4)Frequency of collection:相对于程序执行垃圾收集发生的频率。
(5)Footprint:一些参数的大小,例如堆大小(Heap Size)。
(6)Promptness:对象变为垃圾后到该内存被清理的时间。
此时我们还需要了解一些其他事情。
(1)默认的本文以Hotspot JVM(版本1.5以上) 类型虚拟机为基础讨论。
(2)在J2SE1.4版本之前,JVM 是不支持并行GC的。
(3)名词"Stop-the-world",Stop-the-world 会在任何一种GC算法中发生。Stop-the-world 意味着JVM 因为要执行GC而停止了应用程序的执行。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成。GC优化很多时候就是指减少Stop-the-world发生的时间。
(4)默认本文讨论GC 内存收集区域为Heap,方法区暂不考虑。
下图蓝色的区域是一个典型的对象寿命分布:
X 轴可以理解为对象存活时间。
Y 轴可以理解为对象存活数量。
当经过几次Minor GC 之后大部分的对象已经被清理,证明他们已经死去。从图中曲线可以看出,即使有大量的对象被创建出来,但绝大部分却是“昙花一现”,很快就已经死去,只有很少量的对象会一直存活下来。
默认的Hotspot 系列虚拟机采用分代方式对Heap 内存进行管理与垃圾清除。分代收集算法就是根据对象的不同生命周期分别管理,HotSpot JVM 中将对象分为我们熟悉的“新生代”,“老年代”和“永久代”分别管理。这样做的好处就是可以根据不同类型对象进行不同策略的管理。
Heap Memory 被分为两大区域:
- Young/New Generation 新生代
新生对象放置在新生代中,新生代由Eden 与Survivor Space 组成。
- Old/Tenured Generation 老年代
老年代用于存放程序中经过几次垃圾回收后还活动的对象。
(1)Young/New Generation 新生代
程序中新建的对象都将分配到新生代中,新生代又由Eden(伊甸园)与两块Survivor(幸存者) Space 构成。Eden 与Survivor Space 的空间大小比例默认为8:1,即当Young/New Generation 区域的空间大小总数为10M 时,Eden 的空间大小为8M,两块Survivor Space 则各分配1M,这个比例可以通过-XX:SurvivorRatio 参数来修改。Young/New Generation的大小则可以通过-Xmn参数来指定。
Eden:刚刚新建的对象将会被放置到Eden 中,这个名称寓意着对象们可以在其中快乐自由的生活。
Survivor Space:幸存者区域是新生代与老年代的缓冲区域,两块幸存者区域分别为s0 与s1,当触发Minor GC 后将仍然活动的对象移动到S0中去(From Eden To s0)。这样Eden 就被清空可以分配给新的对象。
当再一次触发Minor GC后,S0和Eden 中活动的对象被移动到S1中(From s0To s1),S0即被清空。在同一时刻, 只有Eden和一个Survivor Space同时被操作。所以s0与s1两块Survivor 区同时会至少有一个为空闲的,这点从下面的图中可以看出。
当每次对象从Eden 复制到Survivor Space 或者从Survivor Space 之间复制,计数器会自动增加其值。 默认情况下如果复制发生超过16次,JVM 就会停止复制并把他们移到老年代中去。如果一个对象不能在Eden中被创建,它会直接被创建在老年代中。
(2)Old/Tenured Generation 老年代
老年代用于存放程序中经过几次垃圾回收后还活动的对象,例如缓存的对象等,老年代所占用的内存大小即为-Xmx 与-Xmn 两个参数之差。
当新生代内存被占满后,新生代的收集器(一般为'minor collection')就会对新生代进行垃圾收集执行工作。当老年代或永久代被占满后,通常是full collection(或被称为major collection)就会执行垃圾清理。这样所有分代内存都会被清理干净。
一般情况下,新生代会被专门的收集算法首先清理。这种算法是专为新生代所设计的,所以这种识别新生代中垃圾的算法通常是最有效的。类似的老年代也有专门的垃圾清理算法支持。
在Hotspot JVM 中的几种GC 类型:
1.Serial Collector
串行收集,在同一时间只会执行一件垃圾清理任务。例如,即使当多个CPU 是可用的,但却只有一个CPU 是用于执行垃圾收集。也就是说在串行收集器下,所有任务将按顺序执行。
新生代中串行收集器如何工作
Eden 中还活动的对象会被拷贝至初始为空的survivor space,在图中被标为'To'空间。被拷贝对象中不包括那些因为过大,'To'无法容纳的对象,而这样的对象会被直接复制到老年代。
如果另一块survivor space(图中标为From)中存在相对比较年轻(young)并且仍活动的对象,则会被一同复制到另一块'To' 中(即从From 复制到To)。
复制开始前(红色部分为垃圾):
如果此时To 空间已满,那些Eden 里仍旧活动或尚未复制到From 空间的里的对象,将一直活动下去,不论经过多少次新生代垃圾收集。也就是说既然你无法给我提供容身之处,那么我将肆无忌惮的逍遥下去。
在活动对象复制完成之后,Eden 或From 空间中的剩余对象均会被定义为not live,他们不再需要进行检查。这些对象已经不会再被我们使用,也就是我们所说的“垃圾”,这些垃圾会在下次垃圾清理后消失。
清理及复制完成后:
老年代中串行收集器如何工作
在老年代与永久代中,串行垃圾收集器使用mark-sweep-compact 收集算法。mark-sweep-compact 算法有3个阶段:mark(标记阶段),sweep(清扫/清除阶段),compact(压缩阶段)。
标记阶段:收集器首先确认哪些对象还活动着。
清扫阶段:清扫整个老年代被标记过的垃圾。
压缩阶段:清扫完成之后收集器执行移动压缩(sliding compaction),将live 对象移动到老年代内存空间的起始部分(永生代中情况类似),这样在老年代内存空间的尾部会产生一个大的连续空间,方便在给新对象分配空间的时候执行bump-the-pointer。
下图为经过垃圾收集及压缩过后的老年代内存情况:
串行收集器被大多数客户端程序所选择,因为这样的程序并不会对暂停时间有严格要求。
从J2SE 5.0发行版后,串行收集器在那些不是服务级别的机器上被自动选为默认的垃圾收集器。可以声明-XX:+UseSerialGC 选项使用串行收集器。
总结
串行收集器的优点:简单易用,非常容易管理。
串行收集器的缺点:效率不高,无法处理较大规模垃圾清理情况,更适用于客户端程序。
2.Parallel Collector
并行收集器,也被称为吞吐量收集器,当使用并行收集器时,原本的垃圾收集任务会被分割成不同的子任务,并且这些子任务同时会分配在不同CPU 下执行。这样同时操作可以做到更加快速的垃圾清理,但也会消耗更多的系统资源和产生清理不完全(潜在碎片)的情况。
在新生代中,并行收集器使用并行版本的串行收集器收集算法,所以新生代的并行回收算法和串行收集器是一样的,只是增加了并行的能力,新生代的并行收集器仍然是stop-the-world 和coping收集器,但通过在多个CPU 中并发运行,降低了GC 的开销并提升了应用程序的吞吐量。
原本新生代中的复制任务在并行收集器中会被分为多个任务,例如:
假设任务1执行时间1秒,任务2执行时间2秒,任务3执行时间3秒。
在串行收集器中三个任务将被顺序执行,例如:1-->2--3,执行时间为三者花费时间之和则为6秒。
但在并行收集器中利用多CPU优势,三个任务将会同时进行,所以执行时间为最长任务执行时间则为3秒。并行收集器大大的缩短了垃圾收集过程的执行时间,下图为两种收集器的对比:
老年代的并行回收使用的也是串行的mark-sweep-compact 回收算法,特别注意的是并行收集器对老年代的回收并没有并行处理的能力,也就是说并行收集器只对新生代并行回收。
并行处理器可以在多CPU 硬件支持下更迅速的执行垃圾清理,从而缩短程序暂停时间,可以声明-XX:+UseParallelGC 选项使用并行收集器。
总结
并行收集器的优点:充分利用硬件资源,垃圾清理工作较串行垃圾收集器更为迅速,效率更高。
并行收集器的缺点:硬件资源消耗更多,老年代下并行收集器与串行收集器相同,在某种程度上存在垃圾清理不完全的情况。
3.Parallel Compacting Collector
并行压缩收集器是在J2SE1.5后引入,与并行收集器最大的不同是对老年代的回收使用了不同的算法,并行压缩收集器最终会取代并行收集器。
新生代中使用并行压缩回收
并行压缩收集器对新生代的回收算法跟并行收集器相同。
老年代中使用并行压缩回收
并行压缩收集器同样还是会引起stop-the-world 效应,并行主要是体现在sliding compaction 上。收集器使用了3个阶段:
首先,整个代在逻辑上都分配成几个固定大小的region(区域)。
然后,进入Marking 阶段,在应用程序中可以直接引用到的活动对象被多个GC 线程所划分掉,然后所有的活动对象就可以以并行地方式来实现对它们的标注。当某个Object 被鉴定为活动对象的时候,就会更新这个对象所在区块的大小以及该对象位置的信息。marking 结束之后是summary 阶段,summary 阶段操作的是region 而不是对象了。由于每次的GC 的压缩都会每一个代的左边的部分区域活动对象密度特别高,保存了多数活动对象。对这样的高密度活动对象的区域进行压缩往往不划算。所以在summary 阶段会从最左边的区域开始检验每个区域的密度,当进行到某个区域中能回收的空间达到了某个数值的时候,那么收集器会判定该区域以及该区域右边的那些区域都是值得进行回收的。该区域左边的区域都会被标识成密集,不会有对象移动到这些密集区域去,而该区域和右边的区域之后都会被进行压缩,回收空间的操作。在summary 阶段会计算和保存每个活动对象在每个压缩区域的第一个字节的新位置。summary 阶段目前还是串行操作,虽然并行是可以实现的,但重要性不如对marking 和压缩阶段的并行来的重要。
最后,压缩阶段,收集器利用summary 阶段生成的数据识别出有哪些区域是需要装填的,每个GC 线程就可以独立的将数据拷贝到这些区域中。这个过程就会heap 在一端很密集而另一端存在大块的空闲块。
并行压缩收集器适合运行在多个CPU的机器上,而且较之并行收集器增强了对老年代的并行回收,减少了系统停顿的时间,可以声明-XX:+UseParallelOldGC 选项使用并行压缩收集器。
总结
并行压缩收集器的优点:充分利用硬件资源,较之并行收集器增强了对老年代的并行回收,收集器更为迅速,效率更高。
并行压缩收集器的缺点:硬件资源消耗更多,在某种程度上存在垃圾清理不完全的情况。
4.Concurrent Mark-Sweep (CMS) Collector
在很多应用中,更加注重快速的相应时间而不是end-to-end 吞吐量(对于end-to-end 概念我也无法解释的很正确,希望了解的朋友补充)。新生代的垃圾回收通常不会造成长时间的应用程序中断,但是,对于老年代,特别是当Heap 已使用量比较大的时候会导致长时间的程序中断(虽然这种情况不常发生)。Hotspot JVM 引入CMS 的目的就是为了解决这个问题。
新生代中使用CMS
收集方式与并行收集器一致。
老年代中使用CMS
CMS 对老年代的回收多数是并发操作。垃圾收集循环开始的时候需要一个短暂的暂停,称之为初始标记(initial mark),这个阶段会识别出那些直接被引用的活动对象。然后进入了并发标记阶段(concurrent marking phase),收集器会从集合中标记所有可达的活动对象。
与此同时应用程序也在运行,那就无法保证所有的活动对象都会被识别、标记出来。于是应用程序会再次被暂停,在这个再标记(remark)阶段,收集器会访问在并发标记阶段中被修改过的对象并完成标记。由于再标记阶段较之初始标记更重要,所以会并发运行多个线程来提升效率。
在完成了再标记之后,Heap 中所有的活动对象都已经被标记出来,所以后续并发清扫阶段需回收的所有垃圾就已经被确认,接下来就可以运行并发清理了。
因为一些任务,如在再标记阶段重访对象,将增加收集器的工作量,同时开销也会增加。所以对于大多数收集器而言试图减少停顿时间的副作用。
CMS 收集器是一个无压缩的收集器。也就是说那些被释放的空间不会像并行压缩收集器那样自动整理,使Heap 尾端留有大片空闲内存空间,如图所示:
而且由于空闲空间是不连写的,收集器就必须要保存一份可用空间的列表。当需要分配对象的时候,收集器就要通过这份列表找到足够容纳新对象的空间位置,这就导致内存分配效率会比bump-the-pointer 算法差。由于老年代的分配效率下降将直接影响到新生代回收过程中转移至老年代的效率。
另外,CMS 较之前的几种收集器需要更大的Heap,原因是在标记过程中,应用程序同时在运行,同时在分配对象,因此老年代也同时在增长。此外,虽然活动对象在标记阶段都会被识别出来,但有些在标记阶段成为垃圾的对象并不能同时被回收,只能等到下次垃圾收集的时候才能被回收。
最后,由于没有压缩,所以就容易出现内存碎片。为了解决这个问题,CMS 会分析popular 对象的大小来预估下一步可能的需求,然后可能会对空闲的内存块分割或合并。CMS 不会等到老年代满的时候才运行内存回收,而是提前清理出内存空间。所以CMS 会利用之前内存回收的统计数据(收集所需要的时间、老年代被占满的时间等等),然后选择一个合适的开始回收时间。CMS 在老年代的内存占用率到达某个阀值的时候也会进行主动回收。这个阀值可以通过–XX:CMSInitiatingOccupancyFraction=n 参数来定义,缺省值是68,即68%。
总之,CMS较之并发收集器以某些时候稍微增加新生代的回收时间、增加Heap 的使用量、减少一些吞吐量为代价减少了老年代回收过程中的停顿时间,而且CMS 会要求在应用程序运行过和收集器分享处理器资源。对那些会产生比较大老年代的应用程序而言,如果运行在多处理器上,CMS 是一个不错的选择。可以声明-xx:+UseConcMarkSweepGC 选项使用CMS。如果你还想让CMS 运行与增量模式下,则可声明–XX:+CMSIncrementalMode 选项启用增量模式。增量模式指的是把收集器的工作分成多个时间块,然后在两次新生代的回收期间加以运行,这种方式可以更进一步减少暂停的时间。
总结
CMS 收集器的优点:对于老年代使用率比较高的应用程序适合CMS 收集器,对停顿时间有较严格要求的程序也比较适合使用CMS 收集器。
CMS 收集器的缺点:CMS 的缺点也比较明显,CMS会牺牲更多的硬件资源、吞吐量及Heap使用量等,所以在Java1.7之后引入了G1 收集器来全面替代CMS。
5.Garbage-first(G1,Java1.7正式引入)
Garbage-first Garbage Collector,简称G1 GC,是最终将用于代替Concurrent Mark-Sweep Garbage Collector(CMS GC)的新一代垃圾收集器,JDK1.6 update 14及以后版本的JVM 中已经引入了G1 GC。
G1 是一个适用于服务器端、大内存、多CPU情景的垃圾收集器,主要目标是在维持高效率回收(high thoughput)的同时,提供软实时中断特性。用户可以指定一个时间上限,如果垃圾回收导致的程序暂停超过了用户设定的时间上限,会打断垃圾回收,恢复程序的执行。
G1 的原理在于将堆划分成等一系列大小的区域,每一个区域都有一个对应的remembered set 结构,用来记录指向这个区域中的地址的其他区域的指针。 在垃圾回收时,选择记录最少的一个区域进行,按找这种方式选择出来的区域,通常是有用数据最少、垃圾最多的区域,这也就是“Garbage-first”名称的由来。假如没有外部的指针指向这个区域,就可以直接回收整块区域而不用进行内存Copy,可以通过声明-XX:+UseG1GC 选项来使用G1收集器。
G1 收集器我会专门拿出一节来介绍。
最后是对于GC 类型的使用情况分类:
篇幅有限,GC 更高级及相关优化等内容会在其他章节展现。
相关推荐
本文档是一份详细探讨Java垃圾回收机制及其影响的白皮书,标题为《Understanding Java Garbage Collection v4.pdf》,旨在帮助Java开发者和架构师理解垃圾回收器的应用行为、特性和机制,并在Java平台上选择和调整...
《Plumbr Handbook Java Garbage Collection》是一本专注于Java垃圾收集机制的详细指南,旨在帮助读者理解并优化Java应用程序中的内存管理。本手册由Plumbr的联合创始人撰写,Plumbr是一家专注于JVM性能监控的产品...
根据提供的文件信息,以下是对《The Java Garbage Collection Mini Book》这本书的主要知识点梳理和说明: 标题说明:《The Java Garbage Collection Mini Book》是一本专注于Java垃圾回收机制的小册子,由InfoQ...
Java垃圾回收(Garbage Collection,简称GC)是Java运行时环境(JRE)中的一个关键特性,它自动管理对象的生命周期,释放不再使用的对象所占用的内存空间。在Java中,对象在不再被任何引用链可达时,即被视为垃圾,...
Java是一种高性能、跨平台的面向对象编程语言。它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势...
《垃圾收集手册》是关于自动内存管理的一本权威著作,主要探讨了计算机程序中的垃圾收集(Garbage Collection, GC)技术。垃圾收集是现代编程语言中一个至关重要的部分,它负责自动识别并释放不再使用的内存空间,...
垃圾回收(Garbage Collection,简称GC)是Java语言的一个重要特性,它自动化地管理程序中的内存分配与释放,避免了传统C++等语言中的内存泄漏问题。本文将围绕Java垃圾回收这一主题,展开一系列关键知识点的详细解析...
为了更好地进行垃圾回收调优,手册还介绍了一系列有用的工具和技术,比如JVisualVM、GC日志分析工具等,这些工具可以帮助开发者更高效地识别和解决问题。 ##### 7. 垃圾回收调优:实践案例 最后,通过一系列具体的...
本文将详细介绍垃圾回收的工作原理,分析不同JVM使用的GC算法,并对开发者和架构师如何做出更明智的选择提供建议。 JVM垃圾回收器主要分为以下几种类型: 1. 分代(Generational)垃圾回收器: 分代回收器是基于...
本文将详细介绍Java垃圾回收机制的工作原理、各个阶段的执行过程、不同的垃圾回收器类型、Java中的引用类型等。 Java垃圾回收机制的工作原理 ------------------------- Java垃圾回收机制的工作原理是,当一个对象...
一、IBM Garbage Collection(GC) IBM GC是IBM J9 JVM中的内存管理机制,它的主要任务是自动释放不再使用的对象所占用的内存空间。GC的工作涉及到对象的分配、存活判断、内存回收以及内存区域的调整等多个环节。...
Java垃圾回收机制是Java编程语言中的一项核心特性,它负责自动管理程序中的内存分配和释放,以避免内存泄漏和资源浪费。在Java中,程序员无需手动进行内存管理,因为垃圾回收器会识别并清理不再使用的对象,从而释放...
"03 GarbageCollection.zip"这个压缩包文件,其标题暗示了我们将探讨的是垃圾收集(Garbage Collection, GC)这一核心概念,特别是在数据结构和算法的学习中,理解GC的工作原理对于优化程序性能至关重要。...
垃圾收集(Garbage Collection, GC)是Java虚拟机的一项重要功能,它负责自动管理内存,识别并回收不再使用的对象,以避免内存泄漏。HotSpot虚拟机提供了多种不同的垃圾收集器,每种都有其特定的性能特性和适用场景...
垃圾收集(Garbage Collection, GC)是Java编程语言的一个关键特性,它自动管理程序的内存空间,回收不再使用的对象,防止内存泄漏。GC的工作原理包括标记、清除、压缩等阶段,这些过程会影响应用的运行效率,尤其是...
在IT行业中,垃圾回收(Garbage Collection,简称GC)是一项重要的技术,特别是在使用像Java、Python、Ruby等高级编程语言时。垃圾回收是自动管理内存的一种机制,它负责监测和释放不再使用的内存空间,以防止内存...
垃圾收集(Garbage Collection, GC)是这一过程的核心,它负责识别并回收不再使用的内存空间。本篇文章将深入探讨几种常见的垃圾收集算法,以及它们在Java J2EE、C#、ASP.NET以及JVM中的应用。 1. **标记-清除...