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

Java虚拟机之垃圾收集

 
阅读更多

 

垃圾收集虽说不是JVM规范中的,但是却和很多实际工作有关系,本文就是基于Inside Java Virtual Machine中的垃圾收集整理而来。

术语解释

为什么要使用垃圾收集

垃圾收集算法

火车算法

终结

可触及对象的生命周期

 

术语解释

垃圾收集(Garbage Collection)就是自动释放不再被程序所使用的对象的过程。

Java虚拟机规范不要求任何特定的垃圾收集技术,因此这并不是描述正式的Java垃圾收集堆。

 

为什么要使用垃圾收集

更精确、更新的说法应该是“内存回收”。

当一个对象不再被程序所引用时,它所使用的堆空间可以被回收,以便被后续的新对象所使用。垃圾收集器必须能够断定哪些对象是不再被引用的,并且能够把它们所占据的对空间释放出来。在释放不再被引用的对象的过程中,垃圾收集器运行将要被释放的对象的终结方法(finalizer)。

除了释放不再被引用的对象,垃圾收集器还要处理堆碎块。这些堆碎块主要是由于不断创建和释放对象造成的。

JVM具有垃圾收集器的优劣:

  • 可以提高生产率。由JVM专门负责而程序员不需要专门关注;
  • 帮助程序保证完整性。垃圾收集是Java安全策略的重要部分,不会由于失误或故意造成崩溃。
  • 加大了程序负担。必须跟踪哪些对象被正在执行的程序所引用,并且动态的终结并释放不再被使用的对象。需要更多的CPU时间,而且对何时释放缺乏控制。

垃圾收集算法

GC算法的两项工作

  • 必须检测出垃圾对象;
  • 必须回收垃圾对象所使用的堆空间并还给程序。

垃圾检测通常通过建立一个根对象的集合并且检查从这些根对象开始的可触及性来实现。如果正在执行的程序可以访问到的根对象和某个对象之间存在引用路径,这个对象就是可触及的。无法被触及的对象被认为是垃圾。

JVM的根对象集合根据实现不同而不同,以下是根对象的来源:

  • 总会包含局部变量中的对象引用和栈帧的操作数栈(以及类变量中的对象引用)。
  • 被加载的类的常量池中的对象引用,比如字符串。
  • 传递到本地方法中的、没有被本地方法“释放”的对象引用。
  • 潜在来源,JVM运行时数据区中从垃圾收集器的堆中分配的部分。

任何被根对象引用的对象都是可触及的,从而是活动的。任何被活动的对象引用的对象都是可触及的。

保守的垃圾收集器

对真正的对象引用与看上去像合法对象引用的基本类型之间的差别是否区分。

区分活动对象和垃圾的两个基本方法

  •   引用计数
    • 通过为堆中的每一个对象保存一个计数来区分活动对象和垃圾对象,这个计数记录了对那个对象的引用次数。
    • 一个对象被垃圾收集后可能导致后续其它对象的垃圾收集行动。
    • 好处是可以很快执行,交织在程序的运行之中,对实时环境有利。
    • 坏处是无法检测循环,引用计数的增减都会带来额外开销。

    现在已经不为人们所接受。

  • 跟踪

     

    • 实际上跟踪从根节点开始的引用图,在追踪中遇上的对象以某种方式打上标记(要么在对象本身设置标记,要么使用一个独立的位图来设置标记),当追踪结束时,没有打上标记的对象就被判定是不可触及的,可以被当垃圾回收。
    • 基本的追踪算法被称作“标记并清除”,指出了实际的两个过程。JVM中,清除阶段必须包括对象的终结。

对付对碎块的策略

压缩和拷贝,都是通过快速地移动对象来减少堆碎块。

l  压缩收集器。

  • 把活动的对象越过空闲区滑动到堆的一端,这个过程中,堆的另一端出现一个大的连续空闲区。所有被移动的对象的引用也被更新,指向新的位置。
  • 可以通过间接对象引用层来使更新被移动对象的引用变得简单,但多一层会带来性能损失。

l  拷贝收集器。

  • 把所有的活动对象移动到一个新的区域。好处是可以在从根对象开始遍历的过程中随着发现而被拷贝。
  • 一般的拷贝收集器算法:停止并拷贝。代价是对于指定的堆需要两倍大小的内存。

按代收集的收集器

特点观察:

l  大多数程序创建的大部分对象都具有很短的生命期;

l  大多数程序都创建一些具有非常长生命周期的对象。

简单的拷贝收集器浪费效率的主要原因:每次都把这些生命周期很长的对象来回拷贝,消耗大量时间。

按代收集的收集器通过把对象按照寿命来分组,更多的收集那些短暂出现的年幼对象,最年幼的那一代进行最频繁的垃圾收集。

把堆按照对象年龄层分解都可以提高最基本的垃圾收集算法的性能。

自适应收集器

利用以下事实:某些情况下某些垃圾收集算法工作的更好,而另外一些收集算法在另外的情况下工作的更好。根据监视堆中的情形对应的调整。

 

火车算法

垃圾收集算法与明确释放对象相比的缺点:程序员对安排CPU时间进行内存回收缺乏控制。

垃圾收集一般都会停止整个程序的运行来查找和收集垃圾对象,这可能会引起停顿或迟钝。如果可能导致用户可觉察到的停顿或者使程序无法适应实时系统的要求,这种算法被称为破坏性的。

垃圾收集算法的一个目标就是使本质上的破坏性尽可能少,如果可能,尽可能消除这种破坏性。

渐进式收集算法就是通过不试图一次性发现并回收所有不可触及对象,而是每次发现并回收一部分。

限时渐进垃圾收集器可以消除用户可察觉到的垃圾收集停顿。

通常渐进式收集器都是按代收集的收集器,大部分调用中,都是调用堆的一部分。按代收集的收集器把堆划分为两个或多个年龄层,每一个都拥有自己的子堆。除了最高寿的那个年龄层(成熟对象空间)之处,每一个子堆中都可以给定一个最大尺寸。成熟对象空间无法给定最大尺寸。

火车算法的目的是为了在成熟对象空间提供限定时间的渐进收集。

组织:

把成熟对象空间划分为固定长度的内存块,块叫做车厢。算法每次在一个块中单独执行。

每个块属于一个集合,这个集合叫做火车。

集合内的每个块排了序,集合本身也排了序。

成熟对象空间扮演火车站的角色。

总体顺序约定:号码较小的火车总是更早出现的火车。

新对象到达火车站的两种方法:打包成车厢,挂接到除了号码最小之外的火车的尾部;或者作为一列新的火车开进车站;

车厢收集:

每一次执行的时候,要么收集最小数字火车中的最小数字车厢,要么收集整列最小数字火车。

1) 首先检查指向最小数字火车中任何车厢的引用,如果不存在任何来自最小数字火车以外的引用指向它内部包含的对象,那么整列最小数字火车包含的都是垃圾,可以被抛弃。

可以一次收集大型的、无法在一个块中容纳的循环数据结构。

2) 如果1)中确认最小数字火车都是垃圾,那么归还所有火车中所有车厢的对象并且返回,执行结束。如果不是,则将注意力放到火车的最小数字车厢上,或者转移或者释放车厢中的任何对象。

3) 算法首先把所有被最小数字车厢外部的车厢外部引用的对象转移到其他车厢去。当进行这个移动后,任何保留在车厢内的引用都是没有被引用的,可以被垃圾收集,算法归还整节最小数字车厢占据的空间并返回。

3.1)) 保证整列火车中没有循环的数据结构的关键是算法如何移动对象。

  • 如果正被收集的车厢中有一个对象存在来自成熟对象空间以外的引用,这个对象被转移到正在被收集的火车之外的其他车厢去;
  • 如果对象被成熟对象空间的其他火车引用,对象就被转移到引用它的那列火车中去。
  • 转移过后的对象被扫描,查找对原车厢的引用;发现的任何被引用的对象都被转移到引用它的火车中去,新被转移的对象也被扫描,这个过程不断重复,直到没有任何来自其他火车的引用指向正被收集的那节车厢。
  • 如果接收对象的火车没有空间了,那么算法会创建新的车厢(一节空车厢),并附加到那列火车的尾部。
  • 一旦没有从成熟对象空间外部来的引用,也没有从成熟对象空间内其他火车来的引用。那么这节正在被收集的车厢剩余的外部引用都是来自于同一列火车的其他车厢。算法把堆这样的对象转移到这节最小数字车厢的最后一个车厢去。最后这些对象也被扫描,查找对原车厢的引用,任何新发现的也被转移,不断重复,直到没有任何形式的引用指向被收集的车厢,则然后归还整个最小数字车厢占据的空间,释放对象并且返回。

火车算法的一个重要方面,就是可以保证大型的循环数据会完全被收集,即使他们不能被放置在一个车厢中。

火车算法的目标:提供限定时间内的按代收集的收集器中成熟对象空间的渐进式收集。

记忆集合和流行对象

记忆集合是一个数据结构,包含了所有对一节车厢或者一列车厢的外部引用。算法为成熟对象空间内每节车厢和每列火车都维护一个记忆集合。所以一节特定车厢的记忆结合包含了指向车厢内对象的所有引用的集合。故空的记忆集合就是被遗忘的,不可触及的,可回收的。

记忆集合是帮助火车算法更有效完成工作的技术。

仍然具有破坏性的可能。因为移动一个流行对象所需要的工作几乎是不可能限制的。

终结

一个对象可以拥有终结方法:这个方法在垃圾收集器释放对象前必须运行的。

垃圾收集器必须检查它所发现的不再被引用的对象是否存在finalize()方法。

  • 垃圾收集器必须使用某种方法检测出不再被引用的对象(第一遍扫描);
  • 然后,必须检查不再被引用对象是否声明了终结方法;如果有,执行;
  • 第三,执行了所有终结方法之后,垃圾收集器必须从根节点开始再次检测不再被引用的对象(第二遍扫描)。(必要:因为终结方法可能”复活”了某些不再被引用的对象)。
  • 最后,垃圾收集器才能释放那些在第一次和第二次扫描中发现的都没有被引用的对象。

终结方法只能运行一次,如果运行过,然后被复活,之后也不能再运行。

由垃圾收集器运行程序的终结方法,因此何时运行是不可预测的。应该避免编写程序的正确性依赖于对象的终结方法所运行的时机的方法。

对象可触及性的生命周期

1.2之前,垃圾收集器看堆中的对象有三种状态之一:可触及的、可复活的、以及不可触及的。

1.2中,扩充了三个新状态:软可触及、弱可触及以及影子可触及。因此之前的可触及称之为强可触及的。

引用对象

引用对象封装了指向其他对象的连接。被指向的对象称为引用目标,所有的引用对象都是抽象的java.lang.ref.Reference类的子类的实例。

  • SoftReference
  • WeakReference
  • PhantomReference

强引用禁止引用目标被垃圾收集,而软引用、弱引用和影子引用不禁止。

一旦一个引用对象被创建后,它将一直维持到它的引用目标的软引用、弱引用或者影子引用,直到它被程序或者垃圾收集器清除。要清除一个引用对象,程序或垃圾收集器只需要调用引用对象的clear()方法。这个方法是Reference类定义的。

垃圾收集器在把软引用对象和弱引用对象加入队列的时候,是在它们的引用目标离开相应的可触及状态时;

把影子引用对象加入队列是在引用目标进入相应状态时。

软引用对象和弱引用对象在加入队列之前得到了清除,而影子引用对象会保持影子可触及状态,直到程序显式地清除了引用对象。

缓存、规范映射和临终清理

垃圾收集器对待软、弱和影子对象的方法不同,因为每一种都是被设计为,为程序提供不同的服务。

软引用可以创建内存中的缓存,它与程序的整体内存需求有关。(memory-sensitive cache)。

弱引用可以创建规范映射(canonicalizing mappings),比如哈希表,它的关键字和值在没有其他程序部分的引用时可以从映射中清除。

规范映射:对象实例可以在程序的多个地方同时使用。从而节约存储,但不能防止键(或值)被回收。

影子引用可以实现终结方法以外的更加复杂的临终清理政策。

要使用软引用或者弱引用的目标,可以调用引用对象的get()方法,如果该引用目标还没有没清除,则会得到对引用目标的一个强引用,就可以用通常的方法去使用了,如果引用目标被清除,则返回null。

如果调用影子引用对象的get()方法,只能得到null,即使影子引用还没有清除,也就是说,如果到达了影子可触及状态,则不能再被复活。

虚拟机的实现需要在抛出OutOfMemoryError之前清除软引用,但在其他情况下可以自行选择清理的时间或是否清除它们。实现最好只在内存不敷所需时才去清除软链接,清除的时候先清除老的而不是新的,清除长期未用的而不是最近刚刚用过的。

垃圾收集器在判断出对象处于弱连接状态时就立即清除弱引用。

影子可触及性表示对象即将被回收,可以利用队列中影子应用的到达来触发一些希望在对象生命周期的最后时刻需要完成的动作。完成了影子可触及对象的临终清理后,必须调用指向它的影子引用对象的clear()方法,调用之后就到达了不可触及状态。

软引用、弱引用对象在创建时可以选择不和引用队列关联,而影子引用对象没有关联的引用队列就无法创建实例。

 

备份地址:

Java虚拟机之垃圾收集

 

分享到:
评论

相关推荐

    深入java虚拟机.pdf

    Java 虚拟机的垃圾收集是指在 Java 虚拟机中自动地回收不再使用的对象,以释放内存空间。垃圾收集可以是周期性的,也可以是根据需要进行的。Java 虚拟机提供了多种垃圾收集算法,如标记-清除算法、复制算法、标记-...

    1_Java虚拟机(垃圾收集器和算法).pdf

    Java虚拟机(JVM)是运行Java程序的核心环境,它负责解释执行Java字节码,管理和分配内存,以及进行垃圾收集等任务。本文详细探讨了JVM中的垃圾收集器和垃圾收集算法,以帮助开发者深入理解Java虚拟机的内部运作机制...

    基于嵌入式Java虚拟机的垃圾收集优化算法应用.pdf

    垃圾收集是Java虚拟机中的一个关键功能,它能够自动管理内存,回收不再使用的对象占用的内存空间。然而,不当的垃圾收集算法会导致应用性能降低,尤其是在内存受限的嵌入式系统中。 本论文聚焦于嵌入式Java虚拟机中...

    Java虚拟机规范中文版(JavaSE7).pdf

    这对于优化代码、调试问题、理解垃圾收集机制、内存管理以及JVM调优等方面都非常有用。虽然规范描述的是虚拟机的概念模型,而不是具体的实现,但它为分析和改进Java应用程序的性能提供了理论基础。 总之,《Java...

    Java虚拟机(Java VM) msjavax86 微软java虚拟机

    在性能优化方面,Java虚拟机实现了诸如垃圾收集(Garbage Collection)、动态编译(Just-In-Time, JIT)等机制。垃圾收集自动管理内存,避免程序员手动处理内存泄露问题;JIT编译则是在运行过程中将频繁执行的热点...

    基于实时性的Java虚拟机垃圾收集算法

    ### 基于实时性的Java虚拟机垃圾收集算法:深入解析与优化 #### 引言 垃圾收集(Garbage Collection, GC)是Java语言的重要特性之一,它通过自动化管理内存,减轻了程序员处理内存分配与释放的负担,提高了代码的...

    java虚拟机各种版本

    JVM还有许多优化技术,如分代垃圾收集、并行/并发GC、压缩引用、逃逸分析等,这些都对提升Java应用的性能起到了关键作用。对于开发者而言,理解JVM的工作原理和调优技术,能帮助他们编写出更高效、更稳定的代码。 ...

    java虚拟机

    Java虚拟机(JVM,Java Virtual Machine)是Java平台的核心组成部分,它负责执行Java程序,为Java代码提供了跨平台的运行环境。Java虚拟机的概念始于Sun Microsystems,现在由Oracle公司继续发展和维护。JVM的设计...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

    《深入Java虚拟机(原书第2版)》,原书名《Inside the Java Virtual Machine,Second Edition》,作者:【美】Bill Venners,翻译:曹晓钢、蒋靖,出版社:机械工业出版社,ISBN:7111128052,出版日期:2003 年 9 ...

    深入java虚拟机 高清pdf 高清高清高清

    《深入Java虚拟机》这本书是Java开发者深入了解JVM(Java Virtual Machine)的必备经典之作。它详尽地探讨了Java虚拟机的工作原理、内存管理、类加载机制、字节码执行以及性能优化等多个核心主题,旨在帮助开发者...

    JAVA虚拟机解读入门

    《JAVA虚拟机解读入门》是一本面向初学者的指南,旨在带领读者深入理解Java虚拟机(JVM)的工作原理和内部机制。...通过学习,你将能够揭开Java虚拟机的神秘面纱,为你的Java编程之路打下坚实的基础。

    Java虚拟机规范(Java SE 7).pdf

    通过深入学习《Java虚拟机规范(Java SE 7)》,开发者可以掌握JVM的内存结构,理解类加载过程,了解垃圾收集机制,以及如何有效地利用这些知识来编写更高效、更稳定的Java代码。此外,熟悉JVM规范也能帮助开发者...

    Java 虚拟机面试题全面解析(干货)

    Java虚拟机(JVM)是Java程序运行的核心,它负责在不同操作系统上提供统一的运行环境。对于准备面试或希望深入理解JVM的开发者而言,了解JVM的各个组件和特性是必须的。本文将通过解析Java虚拟机面试题来深入探讨JVM...

    java虚拟机的两本书

    《深入Java虚拟机》通常包含了JVM的详细剖析,涵盖了诸如类加载机制、字节码执行、内存管理、垃圾收集、性能优化等多个关键领域。书中可能详细解释了JVM如何将字节码转换为机器码,以及如何进行动态编译以提升运行...

    java虚拟机中的垃圾收集GC.pdf

    垃圾收集(Garbage Collection,简称GC)是Java虚拟机(JVM)自动管理内存的重要功能之一。通过自动识别并回收不再使用的对象所占用的内存空间,GC极大地简化了开发者的编程工作,避免了手动内存管理可能带来的内存...

    深入JAVA虚拟机 随书源码 JVM规范

    Java虚拟机(JVM)是Java程序运行的核心,它负责解释和执行字节码,为开发者提供了跨平台的运行环境。深入理解JVM对于优化代码性能、排查问题以及提升编程能力至关重要。本篇文章将详细探讨JVM的工作原理、内存管理...

    深入Java虚拟机——本地方法栈.pdf

    除了用户程序的线程,JVM实现还可能包含一些后台线程,如垃圾收集器,这些线程不需要直接对应执行引擎实例。 JVM的指令集是其操作的基础,字节码流由一系列指令组成,每个指令由一个操作码和可能的操作数构成。操作...

    java虚拟机.doc

    Java虚拟机的垃圾收集器(Garbage Collector)负责收集垃圾对象,以释放内存空间。垃圾收集器的算法包括引用计数算法和根搜索算法。引用计数算法是通过给对象添加一个引用计数器来实现垃圾收集的,而根搜索算法则是...

Global site tag (gtag.js) - Google Analytics