学习马士兵老师的课程,根据笔记自己得出以下自己的理解,继续学习后续课程后,再来添加笔记。
什么是垃圾?如何定义垃圾?
栈中 ,每个方法一个栈帧,每个方法结束后,自动释放。这时,堆中有堆空间没有被引用,但是这时每个堆空间都不允许被访问了,这些堆空间就是垃圾。
引一些题外话:java是自动回收垃圾,而c和c++都是手工释放垃圾。
这就存在几个问题:
1.如果堆中的空间一直没有释放,此时这个空间一直被占用状态,这就会导致内存泄漏,泄漏得多了,就导致了内存溢出。
2.如果释放了多次,就可能会导致误删。例如:程序1第一次释放空间后,程序2又访问了该空间,这时因为代码问题,程序1又释放了一次,把程序2引用的空间删除,程序2就会出现异常。
但是不可否认的是他们运行效率都高。
因此推出Java后,就很机智的加入了GC这个概念
GC(Garbage collector) 垃圾回收器
Java垃圾回收器,其采用了引用计数法、Root (根可达)算法
引用计数法
每个对象申请内存的时候,对象的引用数量+1
对象A引用了对象B后,对象A的引用数量-1,对象B的引用数量+1
其优点是:
能快速的删除垃圾,程序暂停时间短
但是有一个很严重的问题,循环引用的话,引用计数法,是无法清除垃圾的。
什么是根可达?
每个栈中的栈帧(方法)都算一个ROOT,如果顺着分支能找到引用的空间都不是垃圾空间,其余的都是垃圾空间。
那要怎么释放呢?有三种方法:
1.标记回收
找到没有被引用到的空间,然后将这些空间进行标记。告诉程序,这些空间已经可以使用了!但是这个处理多次后,就会导致碎片化严重,在堆空间都是断断续续的。
2.Copying
将一个内存空间设置为start、survivor,如果GC入场后,回收掉start空间中的垃圾后,有幸存者,就将这批幸存者都赋值到survivor空间中,然后将start空间内的东西都删除。如此往复进行。但是这会导致内存浪费
3.标记压缩
针对标记回收和copying的缺点,进行标记压缩时,将GC后的所有能被引用的空间都放在前面,垃圾空间都放在后面,再一次进行垃圾回收。
常用的垃圾回收器
分代模型:
分代模型分为了年轻代和老年代。
在年轻代中主要分为了三个空间,aden\survivor1\survivor2,GC进场后,先回收掉aden空间中的大量垃圾,然后将幸存者放入到survivor1,然后将幸存者标记+1,GC再进场后,扫描aden、survivor1,再将幸存者放入到survivor2,然后再将幸存者标记+1,如此往复。
当幸存者标记到大15时,就讲这些幸存者放入到老年代中。
当内存不够时,就会清除老年代。
常用组合
1.serial+serial old
2.parallel scavenge + parallel old
3.CMS + parnew
4.G1
5.ZGC
6.shenandoah
7.epsilon
1、2以及parnew都是
STW(stop-the-world)
GC入场后,让所有线程都停止!等垃圾回收后,再继续运行。
CMS 、G1、ZGC、shenandoah
统称为ConcurrentGC
并发完成垃圾回收
如何查看GC版本
在cmd中输入命令
java -XX:+PrintCommandLineFlags -version
最后的-UseParallelGC
就体现我在使用parallel scavenge + parallel old