Garbage Collection
自动垃圾回收即在堆空间中识别被引用的对象以及未被引用的对象, 然后删除未被引用的对象的过程。
基本步骤:
- Marking(标记): 识别被引用的对象, 以及未被引用的对象。 所有的对象都会被扫描。
- Normal Deletion(正常删除): 删除未被引用的对象, 引用的对象会被保留, 并且memory allocator会保存空闲块的引用。
或:
Deletion with Compacting(删除并压缩): 删除未被引用的对象, 把被引用的对象移动到一起, 方便后面的内存分配。
Generatiional Garbage Collection
标记并压缩对象是不够高效的, 并且多数对象只存活很短的时间, 因此就有了Generational Garbage Collection。
由此, Java堆被分成了三块:新生代, 老年代和永生代, 其中新生代被分为eden, s0, s1三块。
新生代是对象被新建以及变老的地方, 当新生代空间被填满时就会运行minor garbage collection(小型垃圾回收)。
老年代是存储存活时间较长的对象的地方, 基本上jvm会为新生代的对象设置一个阈值, 当新生代的对象经历过指定的次数没有被回收就会被移入老年代。 老年代运行的垃圾回收叫做major garbage collection(大型垃圾回收)。
不论是小型垃圾回收还是大型垃圾回收, 期间都会停止jvm上的所有应用线程, 直至垃圾回收结束。
永生代包含JVM需要的描述类以及方法的元数据信息, 永生代的垃圾回收包括在full gc中, 它会回收不会再被使用的类元数据信息所占用的空间。
垃圾回收机制:
- 任何新建的对象被分配在eden中, s0和s1初始为空。
- 当eden空间满了之后, minor garbage collection被触发。
- 所有的被引用的对象被移到s0空间, 未被引用的对象被删除。
- 当下一次运行minor GC时, eden上的未被引用的对象被删除, 被引用的对象被移到s1, 同时, s0上存活的对象被移到s1上, age加1, 此时eden和s0被清空。
- 下一次运行minor GC时, 发生同样的过程, 但此时是eden和s1被清空, 所有对象移到s0上。
- 当s0和s1上的对象到达了指定了age阈值后, 对象被移动到老年代中。
观察java堆可使用jvisualvm软件, 在jdk的bin目录下, 运行后通过Tools -> Plugins安装Visual GC插件。
安装完成后选择指定的application, 然后选择Visual GC tab。可看到所有的垃圾回收器的运行活动, 包括新生代, 老年代, 永生代空间大小等。
Java中的垃圾回收器
The Serial GC
串行垃圾回收器是java se5和6中默认的垃圾回收器, 所有的minor和major garbage collection是串行运行的。并且它使用标记-压缩的垃圾回收方法。
串行垃圾回收器是当应用程序不要求垃圾回收时间(即应用程序暂停)很短的情况下使用,或者有多个JVM运行在一台机器上。
-XX:+UseSerialGC
The Parallel GC
并行垃圾回收器使用多线程去执行新生代的垃圾回收,但是在老年代运行的依然是串行垃圾回收器。默认有几个CPU核心, 就会有几个线程。
但是在单核CPU上即使指定了并行垃圾回收器运行的依然是串行垃圾回收器。
-XX:+UseParallelGC: 使用并行垃圾回收器
-XX:+UseParallelOldGC: 在新生代及老年代上使用并行垃圾回收器, 并且老年代上会进行对象的压缩, 而新生代运行的是一个copy collector。
copy collector不重新访问标识被引用的对象或未被引用的对象, 它只会把所有存活的对象移到survivor space
The Concurrent Mark Sweep (CMS) Collector
并行标记垃圾回收器回收老年代的垃圾, 它尽可能减少程序暂停的时间。它不会进行对象的copy或compact, 而当一个空间大小不够时, 它会分配一个更大的堆。
-XX:+UseConcMarkSweepGC
The G1 Garbage Collector
Java7中才有的垃圾回收器, 将会取代CMS垃圾回收器, G1垃圾回收器也是一个并行的垃圾回收器。
-XX:+UseG1GC
https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html#RequiredSoftware