原文地址 https://javapapers.com/java/h...java
This tutorial is to understand the basics of Java garbage collection and how it works. This is the second part in the garbage collection tutorial series. Hope you have read introduction to Java garbage collection, which is the first part.
本系列教程用于帮助读者了解 Java 垃圾回收的基本概念和运做机理。本文是系列教程中的第二部分。但愿您已经阅读了前文,即 Java 垃圾回收的介绍。算法
Java garbage collection is an automatic process to manage the runtime memory used by programs. By doing it automatic JVM relieves the programmer of the overhead of assigning and freeing up memory resources in a program.
Java 中的垃圾回收是一种自动处理的机制,它对程序运行期间所使用的内存进行管理,以帮助开发人员从手工分配和释放内存的苦差事中解脱出来。编程
Being an automatic process, programmers need not initiate the garbage collection process explicitly in the code. System.gc() and Runtime.gc() are hooks to request the JVM to initiate the garbage collection process.
做为一种自动运行的机制,Java 垃圾回收无需编程者在代码中手工执行。System.gc()
和 Runtime.gc()
的做用是请求 JVM 启动一次垃圾回收。segmentfault
Though this request mechanism provides an opportunity for the programmer to initiate the process but the onus is on the JVM. It can choose to reject the request and so it is not guaranteed that these calls will do the garbage collection. This decision is taken by the JVM based on the eden space availability in heap memory. The JVM specification leaves this choice to the implementation and so these details are implementation specific.
虽然这样的请求能够令编程者有发起一次垃圾回收的机会,但最终决定权在 JVM 自己,JVM 能够选择拒绝这么作,因此该方法不保证垃圾回收会真的执行。JVM 作出哪一种决定,是基于 eden 区的可用空间大小。JVM 规范容许不一样的实现作出不一样的决定,因此细节方面要看具体的实现。app
Undoubtedly we know that the garbage collection process cannot be forced. I just found out a scenario when invoking System.gc() makes sense. Just go through this article to know about this corner case when System.gc() invocation is applicable.
虽然说垃圾回收不能强制执行,但我仍是发现某些特定场景中调用 System.gc()
是合理的。具体请参考这篇文章。less
Garbage collection is the process of reclaiming the unused memory space and making it available for the future instances.
垃圾回收过程的目的是收回无用的内存空间,以供未来新的对象实例使用。ide
Eden Space: When an instance is created, it is first stored in the eden space in young generation of heap memory area.
Eden 空间:当对象实例建立时,会先存放到堆内存新生代的 eden 空间。oop
NOTE: If you couldn’t understand any of these words, I recommend you to go through the garbage collection introduction tutorial which goes through the memory mode, JVM architecture and these terminologies in detail.
注意:若是你对上面的名词感到不理解,建议先阅读 垃圾回收介绍,该文章对相关的技术名词和概念做了介绍。
Survivor Space (S0 and S1): As part of the minor garbage collection cycle, objects that are live (which is still referenced) are moved to survivor space S0 from eden space. Similarly the garbage collector scans S0 and moves the live instances to S1.
幸存区(S0 和 S1):做为 小型垃圾回收周期 的一部分,依旧被引用的对象实例会从 eden 区移至幸存区 S0。相似的,垃圾回收器在扫描 S0 区后,会将被引用的对象移至 S1。优化
Instances that are not live (dereferenced) are marked for garbage collection. Depending on the garbage collector (there are four types of garbage collectors available and we will see about them in the next tutorial) chosen either the marked instances will be removed from memory on the go or the eviction process will be done in a separate process.
不被引用的对象会被打上回收标记。根据垃圾回收器的不一样类型(教程的下一章节将会介绍四种不一样的垃圾回收器类型),被标记的对象能够被立刻移除,或者将移除工做交给另外的过程来作。ui
Old Generation: Old or tenured generation is the second logical part of the heap memory. When the garbage collector does the minor GC cycle, instances that are still live in the S1 survivor space will be promoted to the old generation. Objects that are dereferenced in the S1 space is marked for eviction.
老年代:老年(或终身)代是堆内存的第二部分。在小型垃圾回收周期完成后,依旧存留在 S1 幸存区的对象实例将被提高至老年代,其他的则会被打上回收标记。
Major GC: Old generation is the last phase in the instance life cycle with respect to the Java garbage collection process. Major GC is the garbage collection process that scans the old generation part of the heap memory. If instances are dereferenced, then they are marked for eviction and if not they just continue to stay in the old generation.
大型垃圾回收:对象实例进入老年代后,就处于生命周期当中的最后阶段。大型垃圾回收过程就是用来扫描整个老年代区域的。若是对象实例被发现再也不被引用,则打上回收标记,不然将依旧存活在老年代当中。
Memory Fragmentation: Once the instances are deleted from the heap memory the location becomes empty and becomes available for future allocation of live instances. These empty spaces will be fragmented across the memory area. For quicker allocation of the instance it should be defragmented. Based on the choice of the garbage collector, the reclaimed memory area will either be compacted on the go or will be done in a separate pass of the GC.
内存碎片化:当实例对象从堆内存中删除时,会留下空白区域。随着程序运行,内存区域当中会遍及此类“孔洞”。为了能更高效的分配内存给新的对象实例,须要对内存区域进行碎片整理。垃圾回收器会有不一样的具体实现,要么在回收过程当中合并空白区域,要么将合并工做交给另外的过程来作。
Just before evicting an instance and reclaiming the memory space, the Java garbage collector invokes the finalize() method of the respective instance so that the instance will get a chance to free up any resources held by it. Though there is a guarantee that the finalize() will be invoked before reclaiming the memory space, there is no order or time specified. The order between multiple instances cannot be predetermined, they can even happen in parallel. Programs should not pre-mediate an order between instances and reclaim resources using the finalize() method.
在删除对象实例、收回内存空间以前,Java 垃圾回收器会调用被回收对象的 finalize()
方法,以便该对象释放其持有的资源。虽然说这点能够获得保证,但调用该方法的顺序和时间是未知的,你没法预测几个要回收的对象谁的 finalize()
方法会被先调用,它们甚至可能并行发生。程序在利用 finalize()
方法时不该该假设存在这样的顺序。
There are different types of references in Java. Instances eligibility for garbage collection depends on the type of reference it has.
Java 当中有几种不一样的引用类型,对象实例是否可回收取决于其被引用属于哪一种类型。
Reference 引用类型 | Garbage Collection 垃圾回收 |
---|---|
Strong Reference 强引用 |
Not eligible for garbage collection 不可进行垃圾回收 |
Soft Reference 软引用 |
Garbage collection possible but will be done as a last option 垃圾回收能够做为最后选项 |
Weak Reference 弱引用 |
Eligible for Garbage Collection 可垃圾回收 |
Phantom Reference 幻引用 |
Eligible for Garbage Collection 可垃圾回收 |
During compilation process as an optimization technique the Java compiler can choose to assign null value to an instance, so that it marks that instance can be evicted.
在编译过程中,做为一个优化技巧,你能够选择让 Java 编译器将 null
值赋给一个对象实例,至关于给该对象实例打上了回收标记。
class Animal { public static void main(String[] args) { Animal lion = new Animal(); System.out.println("Main is completed."); } protected void finalize() { System.out.println("Rest in Peace!"); } }
In the above class, lion instance is never uses beyond the instantiation line. So the Java compiler as an optimzation measure can assign lion = null just after the instantiation line. So, even before SOP’s output, the finalizer can print ‘Rest in Peace!’. We cannot prove this deterministically as it depends on the JVM implementation and memory used at runtime. But there is one learning, compiler can choose to free instances earlier in a program if it sees that it is referenced no more in the future.
上面这个例子当中,lion
变量在声明后就没有再用到了。所以 Java 编译器能够对其进行优化,在声明语句的后面加上一行 lion = null
,此时终结过程打印的“Rest in Peace!”甚至能够发生在“Main is completed.”以前。固然这也不是百分百肯定,由于这取决于 JVM 的具体实现和运行时的内存使用状况。但咱们起码可以学到,编译器能够在发现对象实例再也不被使用时,将其被回收的时机提早。
null
,或者复杂到上面说的状况。这些都由 JVM 的具体实现决定,但目的都是为了尽可能节省内存使用、提高程序的响应和处理能力。为达到这个目的,JVM 实现者能够选择更好的规划和算法来回收内存空间。finalize()
方法以后,JVM 会释放该线程上的全部同步锁。Example Program for GC Scope
一个对象回收的例子:
class GCScope { GCScope t; static int i = 1; public static void main(String args[]) { GCScope t1 = new GCScope(); GCScope t2 = new GCScope(); GCScope t3 = new GCScope(); // No Object Is Eligible for GC // 全部的对象都不能回收 t1.t = t2; // No Object Is Eligible for GC 全部的对象都不能回收 t2.t = t3; // No Object Is Eligible for GC 全部的对象都不能回收 t3.t = t1; // No Object Is Eligible for GC 全部的对象都不能回收 t1 = null; // No Object Is Eligible for GC (t3.t still has a reference to t1) // 全部的对象都不能回收(由于 t3.t 仍然引用原来的 t1 对象) t2 = null; // No Object Is Eligible for GC (t3.t.t still has a reference to t2) // 全部的对象都不能回收(由于 t3.t.t 仍然引用原来的 t2 对象) t3 = null; // All the 3 Object Is Eligible for GC (None of them have a reference. // only the variable t of the objects are referring each other in a // rounded fashion forming the Island of objects with out any external // reference) // 全部对象均可以回收了(三个变量都再也不引用对象实例,原来的三个实例如今成了 // 相互引用的孤岛,再也不被外部变量引用) } protected void finalize() { System.out.println("Garbage collected from object" + i); i++; } }
Example Program for GC OutOfMemoryError
一个内存溢出(OutOfMemoryError)的例子:
Garbage collection does not guarantee safety from out of memory issues. Mindless code will lead us to OutOfMemoryError.
垃圾回收不能保证程序不发生内存溢出。无脑的代码可能会致使 OutOfMemoryError。
import java.util.LinkedList; import java.util.List; public class GC { public static void main(String[] main) { List l = new LinkedList(); // Enter infinite loop which will add a String to the list: l on each // iteration. do { l.add(new String("Hello, World")); } while (true); } }
Output:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.LinkedList.linkLast(LinkedList.java:142) at java.util.LinkedList.add(LinkedList.java:338) at com.javapapers.java.GCScope.main(GCScope.java:12)
Next is the third part of the garbage collection tutorial series and we will see about the different types of Java garbage collectors available.
接下来是垃圾回收系列教程的第三部分,咱们将了解不一样的垃圾回收器类型。