`
iamjordan
  • 浏览: 17115 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java垃圾收集机制小观

阅读更多

java垃圾收集机制

 

     Java 语言可能是使用最广泛的依赖于垃圾收集的编程语言,但是它并不是第一个。垃圾收集已经成为了包括 Lisp、Smalltalk、Eiffel、Haskell、ML、Scheme和 Modula-3 在内的许多编程语言的一个集成部分,并且从 20 世纪 60 年代早期就开始使用了。
     垃圾收集的好处是无可争辩的 ―― 可靠性提高、使内存管理与类接口设计分离,并使开发者减少了跟踪内存管理错误的时间。著名的悬空指针和内存泄漏问题在 Java 程序中再也不会发生了(Java 程序可能会出现某种形式的内存泄漏,更精确地说是非故意的对象保留,但是这是一个不同的问题)。不过,垃圾收集不是没有代价的 ―― 其中包括对性能的影响、暂停、配置复杂性和不确定的结束 (nondeterministic finalization)。
      一个理想的垃圾收集实现应该是完全不可见的 ―― 没有垃圾收集暂停、没有因为垃圾收集而产生的 CPU 时间损失、垃圾收集器不会与虚拟内存或者缓存有负面的互动,并且堆不需要大于应用程序的驻留空间(即堆占用)。当然,没有十全十美的垃圾收集器,但是垃圾收集器在过去十年中已经有了很大改进。


 基本的垃圾收集策略

 

 

       有几种垃圾收集的基本策略:引用计数、标记-清除、标记-整理 (mark-compact) 和复制。此外,一些算法可以以增量方式完成它们的工作(不需要一次收集整个堆,使得收集暂停时间更短),一些算法可以在用户程序运行时运行( 并发收集)。其他算法则必须在用户程序暂停时一次进行整个收集(即所谓的 stop-the-world收集器)。最后,还有混合型的收集器,如 1.2 和以后版本的 JDK 使用的分代收集器,它对堆的不同区域使用不同的收集算法。
所有垃圾收集算法所面临的问题是相同的 ―― 找出由分配器分配的,但是用户程序不可到达的内存块。不可到达是什么意思?可以以两种方式之一访问内存块 ―― 或者用户程序在 根 (root)中有对这一内存块的引用,或者在另一个可到达的块中有对这个块的引用。在 Java 程序中,根是对静态变量中或者活跃的堆栈框架上的本地变量中所包含的对象的引用。可到达的对象集是指向关系下根集的传递闭包。


引用计数
    最直观的垃圾收集策略是引用计数。引用计数很简单,但是需要编译器的重要配合,并且增加了赋值 函数 (mutator)的 开销(这个术语是针对用户程序的,是从垃圾收集器的角度来看的)。每一个对象都有一个关联的引用计数 ―― 对该对象的活跃引用的数量。如果对象的引用计数是零,那么它就是垃圾(用户程序不可到达它),并可以回收。每次修改指针引用时(比如通过赋值语句),或者 当引用超出范围时,编译器必须生成代码以更新引用的对象的引用计数。如果对象的引用计数变为零,那么运行时就可以立即收回这个块(并且减少被回收的块所引 用的所有块的引用计数),或者将它放到迟延收集队列中。
    许多 ANSI C++ 库类,比如 string ,使用了引用计数来提供垃圾收集的特性。通过重载赋值操作符并利用 C++ 作用域提供的确定性结束,C++ 程序可以将 string 类当成是被收集的垃圾那样使用。引用计数很简单,很适用于增量收集,收集过程一般会得到好的引用区域性,但是出于几个理由,它很少在生产垃圾收集器中使 用,如它不能回收不可到达的循环结构(彼此直接或者间接引用的几个对象,如循环链接的列表或者包含指向父节点的反向指针的树)。


 跟踪收集器
    JDK 中的标准垃圾收集器都没有使用引用计数,相反,它们都使用某种形式的 跟踪收集器 (tracing collector)。跟踪收集器停止所有工作(尽管不需要在收集的整个过程中都这样)并开始跟踪对象,从根集开始沿着引用跟踪,直到检查了所有可到达的对象。可以在程序注册表中、每一个线程堆栈中的(基于堆栈的)局部变量中以及静态变量中找到根。


标记-清除收集器
    最早由 Lisp 的发明人 John McCarthy 于 1960 年提出的最基本的跟踪收集器形式是 标记―清除收集器,它停止所有工作,收集器从根开始访问每一个活跃的节点,标记它所访问的每一个节点。走过所有引用后,收集就完成了,然后就对堆进行清除(即对堆中的每一个对象进行检查),所有没有标记的对象都作为垃圾回收并返回空闲列表。图 1 展示了垃圾收集之前的堆,阴影块是垃圾,因为用户程序不能到达它们。
标记-清除实现起来很简单,可以容易地回收循环的结构,并且不像引用计数那样增加编译器或者赋值函数的负担。但是它也有不足 ―― 收集暂停可能会很长,在清除阶段整个堆都是可访问的,这对于可能有页面交换的堆的虚拟内存系统有非常负面的性能影响。
    标记-清除的最大问题是,每一个活跃的(即已分配的)对象,不管是不是可到达的,在清除阶段都是可以访问的。因为很多对象都可能成为垃圾,这意思着收集器花 费大量精力去检查并处理垃圾。标记-清除收集器还容易使堆产生碎片,这会产生区域性问题并可以造成分配失败,即使看来有足够的自由内存可用。


复制收集器
    在另一种形式的跟踪收集器 ―― 复制收集器中,堆被分成两个大小相等的半空间,其中一个包含活跃的数据,另一个未使用。当活跃的空间占满以后,程序就会停止,活跃的对象被从活跃的空间复制到不活跃的空间中。空间的角色就会转换,原来不活跃的空间成为了新的活跃空间。
    复制收集的优点是只访问活跃的对象,这意味着不会检查垃圾对象,也不需要将它们页交换到内存中或者送到缓存中。复制收集器的收集周期时间是由活跃对象的数量 决定的。不过,复制收集器因为要将数据从一个空间复制到另一个空间、调整所有引用以指向新备份而增加了成本。特别是,长寿的对象在每次收集时都要来回复 制。
    复制收集器有另一个好处,活跃对象集会被整理到堆的底部。这不仅改进了用户程序的引用区域性并消除了堆碎片,而且极大地减少了对象分配的成本 ―― 对象分配变成了在堆顶部的指针上增加指针。不需要维护自由列表或者后备列表,或者使用性能最佳或者第一合适的算法 ―― 分配 N 字节就是在堆顶部指针上加 N 并返回前一个值这么简单。
    为非垃圾收集语言实现了复杂内存管理方案的开发人员可能会对复制收集器中廉价的内存分配感到吃惊 ―― 就是指针加法这么简单。以前的 JVM 实现没有使用复制收集器 ―― 这可能是对象分配是昂贵的这一想法是如此普遍的原因之一,开发人员仍然下意识地假设分配成本与其他语言(如 C)类似,而事实上在 Java 运行时中可能要廉价得多。不但是分配成本减少了,而且对于在下次收集之前成为垃圾的对象,解除分配的成本为零,因为既不会访问也不会复制垃圾对象。


 标记-整理收集器
    复制算法的性能很优异,但是它有一个缺点是需要两倍于标记-清除收集器所需要的内存。 标记-整理 算法结合了标记-清除和复制,避免了这个问题,代价是增加了一些收集复杂性。与标记-清除类似,标记-整理是两阶段过程,在标记阶段访问并标记每个活跃对 象。然后,复制标记的对象,使所有活跃对象被整理到堆的底部。如果每一次收集时进行彻底的整理,那么得到的堆就类似于复制收集器的结果 ―― 在堆的活跃部分与自由部分有明确的界线,这样分配成本与复制收集器相当。长寿的对象趋向于沉在堆的底部,这样就不会像在复制收集器中那样反复复制它们。
    那么 JDK 使用了哪种方式进行垃圾收集呢?在某种意义上,使用了所有的方式。早期的 JDK 使用了单线程的标记-清除或者标记-清除-整理收集器。1.2 及以后的 JDK 使用了混合的方式,称为分代收集,其中根据对象的年龄将堆分为几个部分,不同的代是用不同的收集算法收集的。

3
0
分享到:
评论

相关推荐

    24.java垃圾收集机制.zip

    24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集机制.zip24.java垃圾收集...

    Java垃圾收集机制

    Java垃圾收集机制

    java垃圾收集机制

    ### Java垃圾收集机制详解 #### 一、引言 在现代软件开发中,Java作为一种广泛使用的编程语言,其自动管理内存的功能极大地简化了程序设计工作。传统的编程语言如C/C++要求开发者手动管理内存,这不仅增加了编程的...

    Java的垃圾收集机制

    垃圾收集器线程是一种低优先级的线程,在一个Java程序的生命周期中,它只有在内存空闲的时候才有机会运行。它有效地防止了内存渗漏体的出现,并极大可能地节省了宝贵的内存资源。但是,通过Java虚拟机来执行垃圾收集...

    java垃圾收集机制.pdf

    java垃圾收集机制.pdf

    Java垃圾收集机制解析:自动内存管理的艺术

    本文将深入探讨Java中的垃圾收集机制,包括其工作原理、不同类型的垃圾收集器以及它们在实际应用中的使用。 Java语言的一大卖点是它提供了自动内存管理,这意味着程序员不需要手动分配和释放内存,从而减少了内存...

    java垃圾收集机制汇编.pdf

    java垃圾收集机制汇编.pdf

    JAVA垃圾回收机制

    Java垃圾收集器有多种类型,包括: 1. 标记-清除收集器:遍历对象图标记存活对象,然后清理未标记对象,可能导致内存碎片。 2. 标记-压缩收集器:类似于标记-清除,但清理后会压缩存活对象,减少碎片。 3. 复制收集...

    【深入Java虚拟机(8)】Java垃圾收集机制编程开发技

    Java垃圾收集机制是Java开发中的核心概念,它关乎程序的性能和稳定性。深入理解这一机制对于优化应用程序至关重要。本文将详细解析Java虚拟机(JVM)中的垃圾收集工作原理、不同类型的垃圾收集器以及如何通过编程...

    Java垃圾回收机制总结

    Java垃圾回收机制总结 Java垃圾回收机制是Java虚拟机(JVM)中的一种机制,用于防止内存泄露和有效地使用空闲的内存。垃圾回收机制的主要目的是为了回收无用的对象占用的内存空间,使该空间可被程序再次使用。 ...

    Java垃圾回收机制

    ### Java垃圾回收机制详解 #### 一、Java垃圾回收机制概览 Java作为一种现代的、面向对象的编程语言,其一大特色就是引入了自动垃圾回收机制。这一特性极大地简化了开发人员的工作,使得他们不再需要手动管理内存...

    Java垃圾收集必备手册

    Java垃圾收集必备手册 Java 垃圾收集是 Java 语言中的一种自动内存管理机制,旨在释放不再使用的内存资源,以避免内存泄漏和提高程序性能。在这篇手册中,我们将深入探究 Java 垃圾收集的基础知识,包括垃圾收集的...

    垃圾收集机制的基本原理及方法word版

    Java垃圾收集机制是Java虚拟机(JVM)中用于自动管理内存的重要组成部分,它负责识别不再使用的对象并释放其所占用的内存,以防止内存泄漏。理解垃圾收集的基本原理和方法对于编写高效、健壮的Java应用程序至关重要...

    对象的释放和垃圾收集机制.txt

    对于像Java这样的自动管理内存的语言而言,理解其内部的对象释放与垃圾收集机制显得尤为重要。 #### 二、对象的释放 在程序运行过程中,会不断地创建和销毁对象。当一个对象不再被引用时,它就成为了一个无用的...

    漫谈Java垃圾收集器.pdf

    Java垃圾收集器是Java虚拟机(JVM)中的一种自动内存管理机制,旨在释放程序员从手动内存管理的繁琐工作中解脱出来。垃圾收集器通过跟踪对象的引用关系,确定哪些对象是可以被释放的,然后将其回收,以避免内存泄露...

    JAVA垃圾收集.ppt

    java 垃圾整理收集 1垃圾收集器如何做 2垃圾的基本要求

Global site tag (gtag.js) - Google Analytics