垃圾回收

GC Collector

java vs c++

java:自动处理

  • GC处理垃圾
  • 开发效率高,执行效率低
java是有人帮你回收

c++:手动处理,会有很多问题

  • 忘记回收,容易内存泄漏
  • 回收多次
  • 非法访问
  • 开发效率低,执行效率高
c++比较精确,立马回收

寻找垃圾的两种算法

reference count

1600589676870

没有一根线连着它的时候,它就是垃圾

Root Searching(根可达算法)

1600590085064

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之外的其他垃圾回收器不仅在逻辑上,在物理上也是分代的。

    1600653180914

新生代分为:

  • eden(伊甸)默认比例8:是我们刚刚new出来对象之后往里扔的那块区域

  • survivor默认比例1:是回收一次之后跑到这个区域,这里面由于装的对象不同,所以采取的算法不同

  • survicor默认比例1:新生代存活对象特别少,死去对象特别多的算法是Copying

  • old老年代:

    • tenured(终身)

    老年代活着的对象特别多适用于:Mark Compact或Mark Sweep算法

1600653696946

这个对象到底是怎样进行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//打印所有参数

常见的垃圾回收器

1601173495885

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,在并发标记中产生的新垃圾在重新标记中标记
  • 并发清理也会产生新的垃圾,叫做浮动垃圾
posted @ 2020-10-03 09:46  striver-sc  阅读(117)  评论(0编辑  收藏  举报