垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。下面主要说下堆内存的GC。

Minor GC:

       新生代通常存活时间较短,因此基于复制算法来进行回收,(想了解回收算法的请参考:https://blog.csdn.net/qq_39470733/article/details/77447521)所谓复制算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和其中一个Survivor,复制到另一个之间Survivor空间中,然后清理掉原来就是在Eden和其中一个Survivor(from/to)中的对象。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从Eden到 survivor(from/to),最后到老年代。

       Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。 这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。内存默认分配比例时Y:O = 1:2, 而新生代里面的三个内存区域占比为 E:F:T=8:1:1。JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块Survivor 区域是空闲着的。 因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。用javavisualVM来查看,能明显观察到新生代满了后,会把对象转移到旧生代,然后清空继续装载,当旧生代也满了后,就会报outofmemory的异常。

       当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳( 上面已经假设为 from 区域,这里应为 to 区域,即 to 区域有足够的内存空间来存储 Eden 和 from 区域中存活的对象 ),则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 ( 即from 区域 ),并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定),这些对象就会成为老年代。但这也不是绝对的,对于一些较大的对象 ( 即需要分配一块较大的连续内存空间 ) 则是直接进入到老年代。

Full GC:

       Full GC 是发生在老年代的垃圾收集动作,所采用的是标记-清除算法。老年代里面的对象几乎个个都是在 Survivor(from/to) 区域中熬过来的,它们是不会那么容易就 “死掉” 了的。因此,Full GC 发生的次数不会有 Minor GC 那么频繁,并且做一次 Full GC 要比进行一次 Minor GC 的时间更长。 另外,标记-清除算法收集垃圾的时候会产生许多的内存碎片 ( 即不连续的内存空间 ),此后需要为较大的对象分配内存空间时,若无法找到足够的连续的内存空间,就会提前触发一次 GC 的收集动作。

在执行机制上JVM提供了串行GC(SerialGC)、并行回收GC(ParallelScavenge)和并行GC(ParNew)

  • 串行GC:在整个扫描和复制过程采用单线程的方式来进行,适用于单CPU、新生代空间较小及对暂停时间要求不是非常高的应用上,是client级别默认的GC方式,可以通过-XX:+UseSerialGC来强制指定
  • 并行回收GC:在整个扫描和复制过程采用多线程的方式来进行,适用于多CPU、对暂停时间要求较短的应用上,是server级别默认采用的GC方式,可用-XX:+UseParallelGC来强制指定,用-XX:ParallelGCThreads=4来指定线程数
  • 并行GC:与老年代的并发GC配合使用

以上各种GC机制是需要组合使用的,指定方式由下表所示:

 

JVM 参数选项                                                                        

jvm 可配置的参数选项可以参考 Oracle 官方网站给出的相关信息:        http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
下面只列举其中的几个常用和容易掌握的配置选项

-Xms

初始堆大小。如:-Xms256m

-Xmx

最大堆大小。如:-Xmx512m

-Xmn

新生代大小。通常为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。实际可用空间为 = Eden + 1 个 Survivor,即 90% 

-Xss

JDK1.5+ 每个线程堆栈大小为 1M,一般来说如果栈不是很深的话, 1M 是绝对够用了的。

-XX:NewRatio

新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3

-XX:SurvivorRatio

新生代中 Eden 与 Survivor 的比值。默认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10 

-XX:PermSize

永久代(方法区)的初始大小

-XX:MaxPermSize

永久代(方法区)的最大值

-XX:+PrintGCDetails

打印 GC 信息

-XX:+HeapDumpOnOutOfMemoryError

让虚拟机在发生内存溢出时 Dump 出当前的内存堆转储快照,以便分析用

个人感觉这篇博文可以参考学习:https://www.cnblogs.com/hujingnb/p/10181620.html

如有披露或问题欢迎留言或者入群探讨

本文地址:https://blog.csdn.net/qq_39470733/article/details/107352886