垃圾回收
GC Collector
java vs c++
java:自动处理
- GC处理垃圾
- 开发效率高,执行效率低
java是有人帮你回收
c++:手动处理,会有很多问题
- 忘记回收,容易内存泄漏
- 回收多次
- 非法访问
- 开发效率低,执行效率高
c++比较精确,立马回收
寻找垃圾的两种算法
reference count
没有一根线连着它的时候,它就是垃圾
Root Searching(根可达算法)
JAVA程序从main方法开始执行,,一个main方法会启动一个线程,这个线程里面会有线程栈,里面会有main栈帧。从这个main里面开始的这些对象都是我们的根对象,这个main方法调用了别的方法,那别的方法也是我们引用的,都是有用的对象,但是从main开始这个线程栈帧里面这些个叫做根对象,另外一个叫静态变量,一个class有一个静态的变量。load到内存后马上对静态变量进行初始化,所以静态变量访问的到的对象这个叫根对象。还有常量池指的是如果这个class会用到其他的class的那个类的对象,这些事根对象。JNI指的是如果你调用了c和c++写的那些本地方法所用到的那些个类或者对象。
根可达算法:是从根上对象开始搜索
线程栈变量:一个main方法开始运行,main线程栈中的变量调用了其他方法,main栈中的方法访问到的对象叫根对象
静态变量:T.class对静态变量初始化能过访问到的对象叫做根对象
常量池:如果一个class能够用到其他的class的对象叫做根对象
JIN:如果调用的了本地方法运用到本地的对象叫做根对象
根对象:当一个程序马上启动的时候需要的对象叫做根对象
常见的垃圾回收算法
-
Mark-Sweep(标记清除)
算法相对简单
存活对象比较多的情况下效率较高
Mark-Sweep:标记,清除。就是把它标记出来,然后清除。
两遍扫描,效率偏低容易产生碎片
-
Copying(拷贝)
适用于存活对象较少的情况
只扫描一次,效率提高没有碎片
空间浪费
移动复制对象,需要调整对象引用
Copying:就是把内存一分为二,分开之后把有用的拷贝到下面绿色区域,拷贝完后上面全部清掉。
-
Mark-Compact(标记压缩)
不会产生碎片,方便对象分配
不会产生内存减半
Mark-Compact;就是把所有的东西整理的过程,清理的过程同时压缩到头上去。回收之前,有用的全往前面走,剩下的大块空间就全部清出来了。
扫描两次
需要移动对象,效率偏低
堆内存逻辑分区
这个分代算法和垃圾回收器是有关系的,分代这件事由于JVM分了这么多年,分代是存在于ZGC之前的所有垃圾回收器都是分代算法,除了G1之外的其他垃圾回收器不仅在逻辑上,在物理上也是分代的。
新生代分为:
-
eden(伊甸)默认比例8:是我们刚刚new出来对象之后往里扔的那块区域
-
survivor默认比例1:是回收一次之后跑到这个区域,这里面由于装的对象不同,所以采取的算法不同
-
survicor默认比例1:新生代存活对象特别少,死去对象特别多的算法是Copying
-
old老年代:
- tenured(终身)
老年代活着的对象特别多适用于:Mark Compact或Mark Sweep算法
这个对象到底是怎样进行GC过程的:一个对象产生后首先进行栈上分配,栈上如果分配不下会进入伊甸区,伊甸区经过一次垃圾回收之后进入survivor区,survivor区在经过一次垃圾回收之后又进入另一个survivor,与此同时伊甸区的某些对象也跟着进入另外一个survivor,什么时候年龄够了会进入old区,这是整个对象的一个逻辑上的移动过程。
stack:s0-s1之间的复制年龄超过限制时,进入old区,通过参数:-XX:MaxTenuringThreshold配置。
栈上分配
- 线程私有小对象:小对象,线程是私有的
- 无逃逸:就在某一段代码中使用,出了这段代码就没人认识它了
- 支持标量替换:意思是用普通的属性、把普通的类型代替对象就叫标量替代
- 无需调整
栈上分配要比堆上分配要快,在站上分配不下,它会优先进行本地分配
本地分配
在伊甸区好多线程都往里头分配对象,分配对象的时候你这个线程一定会进行空间征用,谁抢到算谁的。多线程的同步效率就会低,所以设计了这么一个机制叫做TLAB
- 占用eden,默认1%,在伊甸区取用百分之一的空间,这块空间叫做这个线程独有。分配对象的时候首先往我线程独有的这块空间里进行分配。
- 多线程的时候不用争用eden就可以申请空间,提高效率
- 小对象
- 无需调整
- 老年代
- 大对象
- eden
java 回车//查看java参数
- 横杠开头都是标志参数
- -X是非标参数
- -XX是不稳定参数
- -Xms:起始的java堆大小
- -Xmx:最大的java堆大小
java的参数
java -XX:printFlagsFinal -version//打印所有参数
常见的垃圾回收器
JDK诞生之后第一个垃圾回收器就是Serial和Serial Old。
常见的垃圾回收器组合有三种(Serial+Serial Old)、(Parallel Scavenge+Parallel Old)、(ParNew+CMS)
Serial
当工作的时候,所有工作线程全部停止,当工作的时候断开的线程则是垃圾,如果突然加入Serial则停止,进行清理垃圾。
Serial Old
这个用在老年代,他用的是mark-sweep的算法,用的也是单线程。
Parallel Scavenge
如果你在JVM没有做任何调优的话,默认的就是Parallel Scavenge和Parallel Old简称PS+PO。
Parallel Old
- a compacting collector that uses multiple GC threads
- 整理算法
ParNew
和Parallel Scavenge没什么区别,就是做了一些增强,便于和CMS一起使用。
CMS
他回收垃圾的线程和工作线程同时进行,叫做concurrent mark sweep(concurrent 并发)。
CMS产生的四个阶段
- 初始标记STW开始的标记
- 并发标记和应用程序同时运行
- 重新标记又是一个STW,在并发标记中产生的新垃圾在重新标记中标记
- 并发清理也会产生新的垃圾,叫做浮动垃圾