java垃圾回收,gc,全称gabage collection
======相关链接=======
gc相关参数请看这里垃圾回收参数
jvm优化请看这里jvm优化
本文面对的都是开发者,所以多余的概念就不说了,直入主题
我们知道所有创建的对象都在堆内存,jvm有五块,堆,虚拟机栈,本地方法栈,方法区和程序计数器,这里只讲堆
我下面分享的垃圾回收机制都是按代分的,首先堆被分成了两块,新生代和老年代,如图
可以看到新生代又有三个空间,伊甸园和两个幸存者
我们先说下新生代的垃圾回收,继续看图
如图可以看到,一切对象创建都是存放在eden,之后进行第一次gc以后会将存活的对象放入其中一个幸存者空间,并且在之后每次gc存活的对象都放在这个空间,直到这个空间满了,此时进行gc将存活的对象放入第二个幸存者空间,之后将第一个幸存者空间清空,这两个幸存者空间反复几次minor gc之后 依旧存活的就可以放入老年代了。
这里插一句,如何判断对象可以被回收了,1.这个对象变得不可到达,为null,2.没有其他对象引用这个对象,其实垃圾回收器自动会帮我们回收,如果想主动的话可以将对象置为null,或者调用System.gc();将对象置为null对程序没有什么影响,但是切记不要使用System.gc();方法,此方法严重影响程序性能,虽然存有这个手动gc的方法,但是请不要调用
我们继续说老年代,老年代一般要比新生代大,所以老年代的gc没有新生代频繁,说到这里,有些开发其实不了解我们为什么要关注gc,这些不是自动执行的么,跟我们有什么关系呢,就我个人粗浅的知识看来,我们进行垃圾回收优化的最大目的就是避免stop-the-world的出现,当它出现的时候系统会停止一切线程,只保留gc线程在运行,想象下你在某网站浏览记录呢,有一瞬间网站对你的请求没有反应了,因为它所有线程都挂起了只有gc线程再跑,那你的体验是不是会很差,所以我们要避免老年代的full gc频繁出现,注意是避免频繁出现,如何避免,合理的新生代老年代内存占比,以及最合适的gc算法,我们下面说下老年代都有哪几种gc算法
1.Serial GC,这种算法分为标记,清除,压缩三个步骤,线程会逐个扫描每一个对象,然后标记出还存活的对象,删除没有存活的对象,然后按顺序填满内存空间
2.Parallel GC,这个算法和第一种比较,区别在于Serial GC只有一个线程执行,而Parallel GC是多线程执行,所以在内存充足并且多核的下 ,这种算法更高效
3.Parallel Old GC,它同第二种算法的区别在于它的三个步骤是,标记,汇总,压缩,汇总是把存活的对象放入指定的内存空间
4.CMS GC,这种垃圾回收方法要求苛刻,他的full gc时间极其短,被称为低延迟gc,在系统响应时间极为苛刻的情况下使用,但是必然也有他的缺点,例如它会占用更多的内存你和cpu进行gc,以及不支持压缩步骤,如果内存碎片过多不得不压缩的情况,那么它gc的时间要比其他方法都长,所以要慎用此方法
5.G1 GC,jdk1.6出现的,但是只是试用,jdk1.7正式推出的,他比上述的gc方法都要快,不过要使用这个方法,你要摒弃新生代和老年代的概念,G1 GC比较麻烦,在这里不多说了,引用网上一段它和CMS GC的比较
G1 GC和CMS GC 看大家如何去选择,具体可以针对不同场景来定,对于gc最后要说的是,我们还要进行gc 监控,来检查我们所设置的内存比例以及gc方法是否合理,要知道每个程序的对象大小,存活时间都是不同的,他们都和stop-the-world有着直接的关系,所以每一个项目都有一个他们特有的最优的内存比例以及gc方法,这就是我们为什么要了解gc,希望大家能从我的分享上认识gc,并且也希望大家提出宝贵意见,让我和大家一起进步
ps:这里补充一下,在老年代存在这么一个card table 它的大小固定,512b,这里存放着老年代里对象引用新生代对象引用的记录,清理新生代对象的时候会查询这个内存块,如果有引用的对象则保留,这个机制可以大大提高新生代gc的效率