GC JVM垃圾回收

来源:互联网 发布:正规网络兼职工作app 编辑:程序博客网 时间:2024/04/30 23:26

GC(Garbage Collector)就是JVM中自动内存管理机制的具体实现。在HotSpot中,GC的工作任务可以划分为两块,分别是内存的动态分配和垃圾回收。在进行内存动态分配之前,GC首先会对内存空间进行划分。目前几乎所有的GC都是采用分大收集算法进行垃圾回收的,所以Java堆区进一步细分的话,还可以划分为新生代(YoungGen)和老年代(OldGen),其中新生代还可以划分为Eden空间、From Survivor空间和To Survivior空间,换句话说,内存空间究竟如何分配完全依赖于GC的设计。当内存空间划分完成后,GC就可以为新对象分配内存空间,并区分出存储在内存中的对象哪些是存活的,那些是死亡的,如果对象已经死亡的,就可以将其标记为垃圾。GC在进行内存回收时应该做到高效,不应该导致应用程序出现长时间的暂停,以及避免产生内存碎片。
垃圾标记:根搜索算法
当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。目前有两种常见的垃圾标记算法,分别是计数算法和根搜索算法。

  • 计数算法:技术算法回味程序中的每一个对象都创建一个私有的引用计数器,当目标兑现被其他存活的对象引用时,引用计数器则会+1,不再引用时则会-1,当引用计数器的值为0时,意味着该对象已经不再被任何对象引用,可以被标记为垃圾对象。但是如果一些明显已经死亡的对象尽管没有被任何存活的对象引用,但是他们之间互相引用,计数器的值永远不会为0,永远不会被清理,造成内存泄漏。
  • 根搜索算法:根搜索算法是以根对象集合为起始点,按照从上到下的方式搜索被根对象集合所连接的目标表对象是否可到达,如果目标对象不可到达,则意味着该对象已经死亡,便可以在InstancceOopDesc的Mark World中将其标记为垃圾对象。

根对象集合包含了以下的五种元素:

  • Java栈中的对象引用
  • 本地方法栈中的对象引用
  • 运行时常量池中的对象引用
  • 方法区中类静态属性的对象引用
  • 与一个类对应的唯一数据类型的Class对象

垃圾回收:分代收集算法

主要分为三种:

  • 标记清除算法(Mark-Sweep)
  • 复制算法(Copying)
  • 标记-压缩算法(Mark-Compact)

标记清除算法:相对与另外两种算法而言,不仅执行效率低下,更重要的是由于被执行回收的无用对象所占用的内存空间有可能是不连续的内存块,不可避免的会产生内存碎片,从而导致后续没有足够的可用内存空间非配给较大的对象。
复制算法:在HotSpot中,Eden空间和另外两种Survivor空间默认所占的比例为8:1:1。当执行一次Minor GC时,Eden空间中存活的对象就会被复制到To空间内,并且之前已经经历过一次Minor GC并在From空间存活下来的对象如果还年轻的话同样也会被复制到To空间内。在以下两种情况下,Eden空间和From空间中的存活对象将不会被复制到To空间内:首先是如果存活的对象的分代年龄超过选项“-XX:MaxTenuringThreshold”所指定的阀值时,将会直接晋升到老年代中,其次是当To空间的容量达到阀值时,存活对象同样也是直接晋升到老年代中。当所有的存活对象被复制到To空间或者晋升到老年代后,剩余的均为垃圾对象,执行Minor GC。当执行玩Minor GC之后,Eden空间和From空间将会被清空,而存活下来的对象则会被全部存储在To空间之内,接下来From空间和To空间将会互换位置。
标记压缩算法:尽管复制算法能够高效的执行Minor GC,但是他却不适合老年代的内存回收。因为老年代中对象的生命周期较长,甚至在某些极端的情况下还能够与JVM的生命周期保持一致,所以如果老年代中的对象也采用复制算法回收内存,不仅需要额外的时间和空间,而且还会导致较多的复制操作影响到GC的执行效率。标记压缩算法:当成功的标记出内存中的垃圾对象后,该算法会将所有的存活对象都移动到一个规整且连续的内存空间中,然后执行Full GC(老年代的垃圾回收)回收无用对象所占用的内存空间。当成功执行压缩以后,已用和未用的内存都各自一边,彼此之间维系着一个记录下一次分配起始点的标记指针,当为新对象分配内存时,则可以使用指针碰撞技术修改指针的偏移量将新对象分配在第一个空闲内存位置上,为新对象分配内存带来便捷。

0 0
原创粉丝点击