前言
对JVM有了一定的认识以后,我们自然而然的就会知道两个异常,一个叫栈溢出(StackOverFlowError),一个叫堆溢出(OutOfMemory)或者说是内存泄漏;在Java内存模型中,栈是每一个线程私有的,随着线程的创建而创建,当栈的内存不足时,就会导致栈溢出的情况;而堆溢出则是指JVM在无法为对象申请到足够的内存空间时而抛出的异常;当我们的程序中出现这两个问题时,此时我们就需要对JVM进行一个调优处理。
调优的核心参数
在Java8以后,内存模型中的永久代已经被移除,取而代之的是元空间;永久代和元空间最大的不同在于前者使用的是JVM的堆内存,但是后者却已经不在JVM中了,它使用的是物理内存,因此在Java8以后,关于JVM的调优我们只需要关注堆中的新生区和养老区,如下图所示
常见配置汇总
垃圾回收机制
当类加载器把新的对象放到堆中时会触发JVM的GC,但JVM在进行GC时,并非每次都对堆内存中的三个区域一起回收的,大部分时候的回收其实都只是针对新生代,因此GC按照回收区域划分可以分为两种,一种是普通GC(Minor GC),一种是全局GC(Full GC);普通GC只针对新生代区域进行垃圾收集操作,因为大多数的Java对象存活率不高,因此普通GC非常频繁,速度也较快;全局GC只针对老年代进行垃圾收集操作,因为老年区的内存空间较大,所以全局GC相对于普通GC的频率较低,速度慢10以上,且全局GC一旦触发,也就意味着系统要考虑内存优化的问题了;JVM垃圾回收机制大致如下图所示
四种垃圾回收算法简介
引用计数法
复制算法
应用在年轻代中的GC算法,该算法的基本思想就是将内存分成两块,每次只用其中一块,当这一块内存用完,就会进行GC,未被回收的对象则复制到另一块区域,依次类推,大致原理如下
标记清除法
用通俗的话来说,标记清除算法就是程序运行期间,当内存快要被耗尽时,GC就会被触发并将程序暂停,随后将要回收的对象标记一遍,最终统一回收这些对象,完成标记清理共作然后让程序恢复运行
标记压缩法
该算法与上标记清除法唯一的区别就是在它的基础上增加了一个压缩的操作,这样就能解决内存碎片的问题,但是却带来来效率不高的问题,其原理大致如下图所示:
总结
对于上述四种算法,单从效率上来说,复制算法无疑是最快的,但是却浪费来较多的内存,标记清除和标记整理方法虽然兼顾了内存碎片这一个问题,但其效率较慢,所以我们无法从绝对意义上说这四种算法谁优谁劣。只是在实际应用中,我们发现复制算法在新生区效果更好一些,而标记清除或者标记整理在养老区则更强劲,因此我们把JVM的垃圾回收称作分代收集算法。