JAVA 的Garbage Collector

下面是一段摘自Thinking in java 4th 的原文片段,尽量翻译了,但是觉得还是像看天书一样,只能对着英文,用英文的语境去理解才行:

In faster schemes, garbage collection is not based on reference counting. Instead, it is based on the idea that any non-dead object must ultimately be traceable back to a reference that lives either on the stack or in static storage. The chain might go through several layers of objects. Thus, if you start in the stack and in the static storage area and walk through all the
references, you’ll find all the live objects. For each reference that you find, you must trace into the object that it points to and then follow all the references in that object, tracing into the objects they point to, etc., until you’ve moved through the entire Web that originated with the reference on the stack or in static storage. Each object that you move through must still be alive. Note that there is no problem with detached self-referential groups—these are simply not found, and are therefore automatically garbage.

        In the approach described here, the JVM uses an adaptive garbage-collection scheme, and what it does with the live objects that it locates depends on the variant currently being used. One of these variants is stop-and-copy. This means that—for reasons that will become apparent—the program is first stopped (this is not a background collection scheme). Then, each live object is copied from one heap to another, leaving behind all the garbage. In addition, as the objects are copied into the new heap, they are packed end-to-end, thus compacting the new heap (and allowing new storage to simply be reeled off the end as previously described).

 

Of course, when an object is moved from one place to another, all references that point at the object must be changed. The reference that goes from the heap or the static storage area to the object can be changed right away, but there can be other references pointing to this object that will be encountered later during the “walk.” These are fixed up as they are found (you
could imagine a table that maps old addresses to new ones).


There are two issues that make these so-called “copy collectors” inefficient. The first is the idea that you have two heaps and you slosh all the memory back and forth between these two separate heaps, maintaining twice as much memory as you actually need. Some JVMs deal with this by allocating the heap in chunks as needed and simply copying from one chunk to
another. The second issue is the copying process itself. Once your program becomes stable, it might be generating little or no garbage. Despite that, a copy collector will still copy all the memory from one place to another, which is wasteful. To prevent this, some JVMs detect that no new garbage is being generated and switch to a different scheme (this is the “adaptive” part). This other scheme is called mark-and-sweep, and it’s what earlier versions of Sun’s JVM used all the time. For general use, mark-and-sweep is fairly slow, but when you know you’re generating little or no garbage, it’s fast. Mark-and-sweep follows the same logic of starting from the stack and static storage, and tracing through all the references to find live objects. However, each time it finds a live object, that object is marked by setting a flag in it, but the object isn’t collected yet. Only when the marking process is finished does the sweep occur. During the sweep, the dead objects are released. However, no copying happens, so if the collector chooses to compact a fragmented heap, it does so by shuffling objects around. “Stop-and-copy” refers to the idea that this type of garbage collection is not done in the background; instead, the program is stopped while the garbage collection occurs. In the Sun literature you’ll find many references to garbage collection as a low-priority background
process, but it turns out that the garbage collection was not implemented that way in earlier versions of the Sun JVM. Instead, the Sun garbage collector stopped the program when memory got low. Mark-and-sweep also requires that the program be stopped.

As previously mentioned, in the JVM described here memory is allocated in big blocks. If you allocate a large object, it gets its own block. Strict stop-and-copy requires copying every live object from the source heap to a new heap before you can free the old one, which translates to lots of memory. With blocks, the garbage collection can typically copy objects to dead
blocks as it collects. Each block has a generation count to keep track of whether it’s alive. In the normal case, only the blocks created since the last garbage collection are compacted; all other blocks get their generation count bumped if they have been referenced from somewhere. This handles the normal case of lots of short-lived temporary objects. Periodically, a full sweep is made—large objects are still not copied (they just get their generation count bumped), and blocks containing small objects are copied and compacted.

The JVM monitors the efficiency of garbage collection and if it becomes a waste of time because all objects are long-lived, then it switches to mark-andsweep. Similarly, the JVM keeps track of how successful mark-and-sweep is, and if the heap starts to become fragmented, it switches back to stop-and-copy. This is where the “adaptive” part comes in, so you end up with a mouthful: “Adaptive generational stop-and-copy mark-andsweep.”

java虚拟机不是使用引用计数的方法进行垃圾回收的,因为引用计数有多余的资源需要管理,而且java    也不是当对象不再使用的时候就立即垃圾回收的,因为垃圾回收会有性能的消耗,这就意味着垃圾回收是需要时间去遍历垃圾的
那么它是基于什么?基于一种方法:存活的对象必须最终要么在栈要么在静态内存中追踪仍然在使用的引用。这个链必须经过几个对象的层,因此,如果你开始在栈和静态内存区域检查所有的引用,那么你就会找到所有存活的对象,对于你找到的每个引用,你必须追踪到它指向的对象,然后,跟着所有对象的引用,追踪到他们指向的对象。直到你完成在栈或者在静态内存中创建的引用的整个网络。你完成的每个对象必须是存活的。
在这里描述的方法里面,JVM使用了自适应的垃圾回收方案,JVM会对依赖当前正在被使用存在的对象做什么,是停止和复制,程序首先会停止,然后复制了的每个存活对象会被放置到其他,摈弃所有的垃圾。除此之外,因为对象会被复制到一个新的堆,他们被端到端打包,因而压缩新的堆,
当然,当一个对象从一个地方移动到另外一个地方,所有指向对象的引用必须被改变,从堆或者静态内存区域取出的对象引用可以被正确改变,但是这个可以是其他指向这个对象的引用会遇到之后在走期间,这个都可以被修复因为他们找到可以想象一个映射旧地址到新地址的表
这里有两个问题叫做低效的复制回收,第一个是你有两个堆和你将两个分离的堆来回搅动所有的内存的思想,维护两次尽你实际需要的更多内存,一些JVM会处理这个通过分配在块的堆作为需求和简单复制从一个块到另外一个。
第二个问题是自身的复制过程,你的程序一旦变得稳定,可能会生成很少或者没有垃圾,尽管是这样,一个复制回收仍然会复制从一个地方的内存到另外一个地方。这就变得很浪费,为了防止这种事情发生,一些JVM会检测没有新的垃圾正在被创建然后转换到不同的方案(这就可适应的方案部分)这个其他方案叫做标记和清除,SUN公司每时每刻在早期的版本中用到的。像一般的使用而言,标记和清除是非常慢的,但是当你知道很少或者没有垃圾生成的时候,就会变得很快。
标记和清除遵循从栈和静态内存开始的同一个逻辑,通过追踪所有的引用去找存活的对象。但是,每次他找到的存活对象,都要通过设置标识来标记,但是对象还没有回收的,仅仅当结束一个标记处理那么清扫就会出现,在清扫期间,死的对象会被释放,然后,没有复制的发生,所以如果一个回收期选择会压缩一个片段的堆,那么通过穿梭对象他一样会这么做。

停止和复制应用于这个垃圾回收的类型没有在后台被处理的思想,而是,当垃圾回收发生时一个程序就会被停止,在Sun的文献中你会找到许多参考文档作为一个低优先级后台进程的垃圾回收,但是事实上,垃圾回收在Sun的早期版本中并没有运行这种方式,而是当内存比较紧张的时候垃圾回收器才会停止程序,标记和清扫也是在程序停止的时候进行的
而正如上次提及的,在JVM描述里面内存是在大块中被分配的,如果你分配了一个大对象,它有自己的块,严格停止和复制请求复制从原始堆中的每一个存活的对象到新的堆,在你可以清除旧的之前,这个翻译到许多内存,用块,垃圾回收通常会复制对象到它回收的死块。每个块有一个生成计数去保持追踪它是否存活,在正常的例子中,仅仅自从上次垃圾回收被紧凑在一起的块被创建。所有的其他块都有他们自己的生成计数泵如果他们已经从一些地方被引用了。这个解决了许多短时间内临时的对象正常例子。定期地,一个完全清扫被启动,大的对象仍然不能被复制,和块包含小的对象是被复制和压缩的。JVM监视垃圾回收的效率他是否浪费了大量的时间,因为所有对象是长时间存活的,然后他转换到标记和清扫,相似地,JVM会保持追踪怎样成功的标记和清扫,如果一个堆开始去称为片段,他转换回停止和复制方案,这是适应性部分彰显能力的地方,所以你最后会用一句话来总结:适应性时代的停止和复制,标记和清扫。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值