




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
How a garbage collector works of Java Language If you come from a programming language where allocating objects on the heap is expensive, you may naturally assume that Javas scheme of allocating everything (except primitives) on the heap is also expensive. However, it turns out that the garbage collector can have a significant impact on increasing the speed of object creation. This might sound a bit odd at firstthat storage release affects storage allocationbut its the way some JVMs work, and it means that allocating storage for heap objects in Java can be nearly as fast as creating storage on the stack in other languages.For example, you can think of the C+ heap as a yard where each stakes out its own piece of turf object. This real estate can become abandoned sometime later and must be reused. In some JVMs, the Java heap is quite different; its more like a conveyor belt that moves forward every time you allocate a new object. This means that object storage allocation is remarkably rapid. The “heap pointer” is simply moved forward into virgin territory, so its effectively the same as C+s stack allocation. (Of course, theres a little extra overhead for bookkeeping, but its nothing like searching for storage.) You might observe that the heap isnt in fact a conveyor belt, and if you treat it that way, youll start paging memorymoving it on and off disk, so that you can appear to have more memory than you actually do. Paging significantly impacts performance. Eventually, after you create enough objects, youll run out of memory. The trick is that the garbage collector steps in, and while it collects the garbage it compacts all the objects in the heap so that youve effectively moved the “heap pointer” closer to the beginning of the conveyor belt and farther away from a page fault. The garbage collector rearranges things and makes it possible for the high-speed, infinite-free-heap model to be used while allocating storage. To understand garbage collection in Java, its helpful learn how garbage-collection schemes work in other systems. A simple but slow garbage-collection technique is called reference counting. This means that each object contains a reference counter, and every time a reference is attached to that object, the reference count is increased. Every time a reference goes out of scope or is set to null, the reference count is decreased. Thus, managing reference counts is a small but constant overhead that happens throughout the lifetime of your program. The garbage collector moves through the entire list of objects, and when it finds one with a reference count of zero it releases that storage (however, reference counting schemes often release an object as soon as the count goes to zero). The one drawback is that if objects circularly refer to each other they can have nonzero reference counts while still being garbage. Locating such self-referential groups requires significant extra work for the garbage collector. Reference counting is commonly used to explain one kind of garbage collection, but it doesnt seem to be used in any JVM implementations. 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, youll 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 youve 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 groupsthese 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 thatfor reasons that will become apparentthe 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 Initialization & Cleanup 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 its what earlier versions of Suns JVM used all the time. For general use, mark-and-sweep is fairly slow, but when you know youre generating little or no garbage, its 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 isnt 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 youll 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 its 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 madelarge 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-and sweep. 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-and sweep.”There are a number of additional speedups possible in a JVM. An especially important one involves the operation of the loader and what is called a just-in-time (JIT) compiler. A JIT compiler partially or fully converts a program into native machine code so that it doesnt need to be interpreted by the JVM and thus runs much faster. When a class must be loaded (typically, the first time you want to create an object of that class), the .class file is located, and the byte codes for that class are brought into memory. At this point, one approach is to simply JIT compile all the code, but this has two drawbacks: It takes a little more time, which, compounded throughout the life of the program, can add up; and it increases the size of the executable (byte codes are significantly more compact than expanded JIT code), and this might cause paging, which definitely slows down a program. An alternative approach is lazy evaluation, which means that the code is not JIT compiled until necessary. Thus, code that never gets executed might never be JIT compiled. The Java Hotspot technologies in recent JDKs take a similar approach by increasingly optimizing a piece of code each time it is executed, so the more the code is executed, the faster it gets.Java垃圾收集器的工作方式 如果你学下过一种因为在堆里分配对象所以开销过大的编程语言,很自然你可能会假定 Java 在堆里为每一样东西(除了 primitives)分配内存资源的机制开销也会很大。不过,事实上垃圾收集器能够深刻影响对象的加速创建。 一开始听起来有些奇怪存贮空间的释放会影响存贮空间的分配,但是这的确是一些 JVMs 的工作方式,并且这意味着 Java 为堆对象分配存贮空间几乎和别的语言里为栈分配存贮空间一样地快。举个例子,你可以认为 C+的堆就如同一个堆放的工场,在这个工场里,每一个对象都立有的地皮占有权不久会被废除无效,并且这块地皮必须重新加以利用。在Java 的 JVM 里,堆的工作方式完全不同;每次为一个新的对象分配存贮空间的时候,它就更像是一个不断向前移动的传送带。 这就意味着对象存贮空间的分配速度明显加快。 在这个过程中,“堆指针”简单地向还没被占用的空间领域移动,所以非常像 C+里栈的分配方式。(当然,记录工作会有一点额外的开销,但是完全不同于 C+里那种在堆放工场里为寻找没被利用的存贮空间而付出的开销。)你或许观察到实际上堆本身并不是一个传送带,如果你真的那样看待堆,你就会启用虚拟内存在硬盘里不断地装卸,结果是看上去你会拥有比实际情况还要多的内存空间。 最终,当你创建了足够多的对象后,你会耗尽内存。 Java 的诀窍就在于垃圾搜集器插手于其中,当垃圾收集器收集垃圾的时候,它会压缩所有堆里的对象以便你能够有效的将堆指针移动到相应的地方从而远离了页面错误。垃圾收集器重新安排了整个过程,这使得分配存贮空间的时候一种高速,无穷闲置的堆模式成为可能。要想理解 Java 的垃圾收集工作,先了解一下别的语言系统里垃圾收集所使用的方案是有帮助的。 一种简单的但却较慢的垃圾收集技术就是引用记数(reference counting)。这种技术意味着每个对象都含有一个引用计数器,每一次一个引用指向那个对象的时候,引用记数就增加1 每一次对象引用离开作用域或者被设置为 null 的时候,引用记数就减1。 因此,应付对象被引用的数量在你的程序的整个生命周期里是一笔较小但却一直持续的开销。垃圾收集器历遍整组对象,当它发现一个引用记数为零的对象时就会释放那个对象的存贮空间。(不过,只要记数为零,引用记数方案通常会立刻释放对象)。 这种方案的一个缺点是如果对象之间循环着互相引用,那么这些对象的引用记数可能为非零,而垃圾收集器依然把它们当作垃圾收集。 定位这种自我引用的对象组需要垃圾收集器付出大量额外的工作。引用记数通常被用来解释一类垃圾收集的工作原理,但是它似乎没被任何一种 JVM 所采纳。有一种执行更快的垃圾收集方案,这种方案中垃圾收集不是建立在引用记数的基础上。相反,它的思想是任何没死的对象最终一定会在栈和静态存贮器里找到相应存活的引用。这种链式的查找方式可能历遍几个层次的对象组。因此,如果从栈和静态存贮器里开始并历遍整个引用组,你会找到所有存活的对象。对于你找到的每个单引用,你必须找到它所指向的对象,然后发觉那个对象的所有引用,接着找到那些引用所指向的所有对象,依次类推,直到你历遍整个由栈和静态存贮器里的引用所形成的网。每个你找到的对象必须还存活着。注意,这里不存在分离的自我引用的对象组他们只是没被查找到,因此被自动当作垃圾。在上述提到的垃圾收集方案中,JVM 使用了一种自适应的垃圾收集方案,它对查找到的存活对象采取的措施依赖于它正在使用的方案变体。其中的一个变体就是 stop-and-copy。 它意味着基于一些明显的原因程序首先停止运行(这不是一种在后台实施的垃圾收集方案)。然后,每一个活着的对象从一个堆里被拷贝到另一个堆里,同时被拷贝的活对象和死的对象被当作垃圾遗弃。并且,当对象被拷贝到新的堆里后,他们在那里被一个挨一个塞紧,因此实现了压缩新堆的目的(而且如前所述,这种方式腾出了压缩后多余出来的新的空间)。当然,对象从一个地方移动到另一个地方的时候,所有指向对象的引用必须相应改变。 指向堆或者静态存贮器里某个被移动对象的引用可以立即得到改变,但是还存在其它后来“在走走”的时候才会碰到的指向该对象的引用。 这些引用一旦发现就会被修改。(你可以想象存在一张映射旧新地址的表)。有两个问题使这种所谓的“拷贝型收集器”缺乏效率。 第一个问题就是你使用了两个堆,为了维护两倍于你实际所需要的内存空间,你得在这两个堆之间来回搅动着整个内存空间。 一些 JVMs 通过依据实际所需来为堆分配大块内存,然后很简单地从一个块拷贝对象到另一个。第二个问题是拷贝过程本身。 一旦你地程序趋向于稳定的时候,它可能生成很少或者几乎不生成垃圾。 然而 stop-and-copy 方案不管这些,拷贝型垃圾收集器依旧把活对象占用的空间从一个地方拷贝到另一个地方,这就形成了浪费。 为了阻止这种情况的发生,一些 JVMs会探测没有新垃圾产生的时机,并且会转向实施另外一个完全不同的垃圾收集方案。 这种不同的方案被称为 mark-and-sweep,并且它是 Sun 的早期 JVM 版本一直使用的方案。 处理一般的垃圾收集工作,mark-and-sweep 表现得相当地慢,但是当你的程序生成很少或者不生成垃圾时,它又运行得很快。Mark-and-sweep 遵循着和 stop-and-copy 一样的逻辑:从栈和静态存贮器里出发,跟踪所有的引用从而找到存活的对象。 不过,每次它找到活对象的时候,那个对象被做以标记,而且对象还不会被收集起来。 只有在整个标记过程完成后,清扫(sweep)工作才真正开始。在清扫过
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 化工农药安全培训总结课件
- 有债务分期还款协议范文5篇
- 别里科夫课件
- 化工三废处理课件
- 兴发安全培训课件
- 兴化消防安全培训费用课件
- 初中家长安全培训知识课件
- 化学教师安全培训课件
- 内蒙消防安全知识培训课件
- 创新安全培训的意义
- 电商直播行业合规性风险管控与流程优化报告
- 第08讲+建议信(复习课件)(全国适用)2026年高考英语一轮复习讲练测
- 政务大模型安全治理框架
- 生态视角下陕南乡村人居环境适老化设计初步研究
- “研一教”双驱:名师工作室促进区域青年教师专业发展的实践探索
- 手卫生及消毒隔离基本知识
- 2025四川能投合江电力有限公司员工招聘11人笔试备考题库及答案解析
- 江苏省徐州市2025年中考英语真题(含答案)
- 包钢招聘考试试题及答案
- 生物安全实验室管理体系文件
- 2025年小学部分国防教育知识竞赛答案
评论
0/150
提交评论