TOC
如果你不合理的设置内存,就会导致新生代内存不充足,然后导致很多对象不停的迁移到老年代去,最后导致老年代也要不停的进行垃圾回收。
最后这频繁的垃圾回收,就会极大的影响系统的性能。
2、先来回顾一个新生代GC的场景
垃圾回收一定会通过一个后台运行的垃圾回收线程来执行他具体的一个逻辑
比如针对新生代我们会用ParNew垃圾回收器来进行回收,然后ParNew垃圾回收器针对新生代采用的就是复制算法来垃圾回收。
这个时候垃圾回收器,就会把Eden区中的存活对象都标记出来,然后全部转移到Survivor1去,接着一次性清空掉Eden中的垃圾对象
接着系统继续运行,新的对象继续分配在Eden中
当Eden再次塞满的时候,就又要触发Minor GC了,此时已然是垃圾回收线程运行垃圾回收器中的算法逻辑,也就是采用复制算法逻辑,去标记出来Eden和Survivor1中的存活对象
然后一次性把存活对象转移到Survivor2中去,接着把Eden和Survivor1中的垃圾对象都回收掉
3、GC的时候还能继续创建新的对象吗?
在垃圾回收的过程中,同时还允许我们写的Java系统继续不停的运行在Eden里持续创建新的对象,目前来看是非常不合适的一个事情。
4、JVM的痛点:Stop the World
所以现在大家就好理解了,我们平时使用JVM最大的痛点,其实就是在垃圾回收的这个过程
因为在垃圾回收的时候,尽可能要让垃圾回收器专心致志的干工作,不能随便让我们写的Java系统继续对象了,所以此时JVM会在后台直接进入“Stop the World”状态。
也就是说,他会直接 停止我们写的Java系统的所有工作线程,让我们写的代码不再运行!
然后让垃圾回收线程可以专心致志的进行垃圾回收的工作
这样的话,就可以让我们的系统暂停运行,然后不再创建新的对象,同时让垃圾回收线程尽快完成垃圾回收的工作,就是标记和转移Eden以及Survivor2的存活对象到Survivor1中去,然后尽快一次性回收掉Eden和Survivor2中的垃圾对象
5、Stop the World造成的系统停顿
因为内存分配不合理,导致对象频繁进入老年代,平均七八分钟一次Full GC,而Full GC是最慢的,有的时候弄不好一次回收要进行几秒钟,甚至几十秒,有的极端场景几分钟都是有可能的。
所以说,无论是新生代GC还是老年代GC,都尽量不要让频率过高,也避免持续时间过长,避免影响系统正常运行,这也是使用JVM过程中一个最需要优化的地方,也是最大的一个痛点。
6、不同的垃圾回收器的不同的影响
比如对新生代的回收,Serial垃圾回收器就是用一个线程进行垃圾回收,然后此时暂停系统工作线程,所以一般我们在服务器程序中很少用这种方式。
但是我们平时常用的新生代垃圾回收器是ParNew,他针对服务器一般都是多核CPU做了优化,他是支持多线程垃圾回收的,可以大幅度提升回收的性能,缩短回收的时间
CMS垃圾回收器,专门负责老年代的垃圾回收
JVM本身的迭代演进,就是不断的在优化垃圾回收器的机制和算法,尽可能的降低垃圾回收的过程对我们的系统运行的影响。
而我们作为一个合格的Java工程师,我们的责任就是尽可能搞懂这些垃圾回收器的运行机制和算法
然后合理的对线程系统优化内存分配和垃圾回收,尽可能减少垃圾回收的频率,降低垃圾回收的时间,减少垃圾回收对系统运行的影响。
所谓的JVM优化,其实指的就是这个
对JVM的运行原理,垃圾回收机制,然后各种生产故障的监控、排查、定位、分析和解决,都有一个本质的能力提升,在公司里绝对可以搞定自己负责的生产系统的JVM故障。