前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM之垃圾回收

JVM之垃圾回收

作者头像
用户1215919
发布2018-02-27 10:35:35
6610
发布2018-02-27 10:35:35
举报
文章被收录于专栏:大大的微笑大大的微笑

对象是否存活: ①.引用计数算法: 描述:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收. 优势:简单高效 缺点:对于循环引用的对象无法回收(两个对象相互引用) ----------------------------------- ②.可达性分析算法: 描述:GC的时候首先会根据一系列可以被定义为GC Roots的对象作为起始点依次往下搜索 这个搜索的路径即为引用链,若对象没有被引用链连接到GC Roots,则将标记为可清除(证明此对象是不可用的。不可达对象。),在下次GC的时候可能会被清除. 在Java语言中,可以被定义为GC Roots的:   虚拟机栈中引用的对象。   方法区中类静态属性实体引用的对象。   方法区中常量引用的对象。   本地方法栈中JNI引用的对象。 优势:弥补了引用计数算法的不足;

再谈引用:

 无论引用计数算法还是可达性分析算法,判断对象是否存活都与引用有关

 引用分为:强引用,软引用,弱引用,虚引用,引用强度依次减弱

①.强引用:

        创建一个对象并把这个对象赋给一个引用变量。被强引用的对象永远不会被垃圾回收 , 即使内存不足的时候。

强引用对象普遍存在,例如:A a = new A();

②.软引用:

        用来描述还有用但并非必须的对象,软引用的对象当系统内存充足时和强引用没有太多区别,但内存不足将要发生内存溢出之前会把这些对象列入回收范围进行第二次回收。若此次回收还没有足够的的内存会抛内存溢出异常.

      通过SoftReference类来实现:

代码语言:javascript
复制
public static void main(String[] args){

  //创建软引用数组
  SoftReference<Book> [] books = new SoftReference[100]; 
  //赋值  
  for(int i = 0; i< books.length ;i++){
    books[i] = new SoftReference<Book>(new Book(""+i ,i));
  }
  
    //测试
  System.out.println(books[1].get());
   //通知系统进行回收
  System.gc();
  System.runFinalization();
  
  System.out.println("---------------");
  System.out.println(books[1].get());
  }
//注意:当系统不足时才会回收软引用的对象。否则不会回收

③. 弱引用:

        用来描述非必须的对象。被弱引用关联的对象生命周期较短,只能生存到下次垃圾收集发生之前, 无论内存是否足够都会回收

弱引用通过WeakReference类来实现:

代码语言:javascript
复制
 public static void main(String[] args) {
   String str = new String("aaa");
//   String str = "aaa"; 这种创建是在常量池中
   //创建一个如引用对象 指向 str对象
   WeakReference<String> wrStr = new WeakReference<String> (str);
  
   str =null;
   //输出
   System.out.println(wrStr.get()); //aaa
   //强制垃圾回收
   System.gc();
   System.out.println(wrStr.get()); //null
 }

④.虚引用:

        软引用和弱引用可以单独使用,虚引用不能单独使用,对象是否有虚引用关联完全不会对其生存时间造成影响。为对象设置虚引用的唯一作用是就跟踪对象被垃圾回收的状态(对象被收集器回收会收到一个系统通知)。

垃圾收集算法: ①.标记清除算法:         描述:最基础的回收算法;算法分为标记和清除两部分 ,首先标记出所有需要回收的对象,其次在标记完成后统一回收掉所有被标记的对象. 缺点: ①.标记和清除过程效率低下; ②.会造成内存碎片,若内存碎片过多可能会导致需要分配较大对象时无法找到足够的连续内存(大的对象放不下.)而不得不提前触发一次垃圾收集动作。 ---------------- ②.复制算法:        描述:    复制算法为了解决效率问题而出现的。它将内存分为大小对等的两部分,每次只使用其中一块,在GC的时候将还在使用的对象复制到另一块区域,整体释放当前区域的内存;        优势:     速度快,实现简单,运行高效,不会造成内存碎片        缺点:     太浪费内存,每次都要牺牲50%的内存,如果生命周期过长的对象逐渐增多,会导致复制趋于频繁从而导致效率下降。         Hotspot虚拟机默认将新生代中的Eden空间,两小块survivor空间,按比例为8:1:1分配, 这样每次GC的时候将Eden,和其中一块survivor中的存活对象复制到另一块survivor中,整体释放,每次只会浪费10%的内存,若存活对象超过10%,此时survivor空间将不够, 因此需要依赖于其他空间进行担保(老年代)。        新生代采用的就是复制算法,因为新生代对象代谢更加频繁,进而导致存活的对象不多,所以需要复制的对象不多,可以提升效率, 而对于老年代则不适用,因为能进入老年代说明该对象生命周期比较长。 ---------------- ③.标记整理算法:       描述 :   是对标记清除算法的一个改良,标记过程不变,在GC的时候将需要清除的对象统一压缩到一边,不需要回收的压缩到另一边,然后整体清除界线一端需要回收的内存空间 适用于老年代收集,因为老年代的GC不是很频繁      优势 : 不会造成内存碎片

---------------------------- 垃圾收集器: 一.新生代收集器:    Serial收集器:     描述: 是最基本,发展历史最悠久的收集器,它是一个单线程收集器,它在进行垃圾回收的时候,必须停止其他所有工作线程,直到它收集结束位置.是client端默认的新生代垃圾收集器.    优势:  简单高效,因为是一个单线程收集器,所以没有线程交互的开销.    不足:  工作时必须停止其他所有工作线程 ParNew收集器:       描述: 是 Serial收集器的多线程版本.其余行为跟Serial收集器相同.是server端首选的新生代垃圾收集器,并且目前只有它可用与CMS收集器(老年代中比较优秀的一个收集器)配合工作.   在设置-XX:+UseConcMarkSweepGC参数后,默认的新生代收集器,也可以使用-XX:+UseParNewGC来强制指定.默认开启的收集器线程数与CPU数量相同,可用使用-XX:ParallelGCThreads参数来限定垃圾收集器的线程数.    优势: 适用于多CPU环境.   不足: 工作时必须停止其他所有工作线程 Parallel Scavenge收集器:  描述:  它是一个吞吐量优先的新生代收集器,它的目标是对于吞吐量可控制,吞吐量 = 程序运行时间 / 虚拟机总运行时间(程序运行的时间 + 垃圾收集的时间).例如虚拟机总运行100m,垃圾收集耗费1m,吞吐量即为99%.    可以从:①.控制最大收集停顿时间(-XX:MaxGCPauseMillis),单位ms,取值范围需大于0,收集时间保证尽可能的不超过这个设定值.;GC停顿时间是以牺牲新生代空间和吞吐量换取的,系统把新生代调小虽然收集速度加快了但是也导致垃圾收集更加的频繁,吞吐量随之下降; ②.设置吞吐量大小(-XX:GCTimeRatio)范围0-100之间,默认值99即为允许最大1%的垃圾收集时间来控制吞吐量;两个参数2选1; 参数 -XX:UseAdaptiveSizePolicy,当开启之后就不需要手工指定新生代大小,Eden与Survivor的比例(-XX:SurvivorRatio),晋升老年代对象的大小(-XX:PretenureSizeThreshold)等参数,虚拟机会根据系统的运行情况收集性能监控信息,动态调整这些参数,以便提供最适合的停顿时间或最大吞吐量,这种调节方式称为GC自适应调节策略。 优势:  可控的最大停顿时间(停顿时间越短,程序响应速度越快,能够提升用户体验)和吞吐量以及自适应调节策略。 不足:  减小最大收集停顿时间会导致收集频率增加,吞吐量下降,反之提高吞吐量则可能会导致停顿时间变长,响应速度降低, 收集期间用户线程暂停。 二,老年代收集器: Serial Old收集器:        描述: 它是Serial收集器的老年代版本,跟Serial一样是一个单线程收集器,使用"标记整理算法"。用于Client模式下的虚拟机使用;在Server模式下作为CMS收集器的后备预案。JDK1.5及以前配合Parallel Scavenge收集器使用。       优势:不会造成内存碎片       不足: 同样收集阶段暂停其他所有用户线程。 Parallel Old收集器:         描述:  作为Parallel Scavenge收集器的老年代版本,同样是一个多线程收集器,使用"标记整理算法"。JDK1.6才开始提供与Parallel Scavenge收集器组合使用。         优势: 同样注重吞吐量.不会造成内存碎片         不足: 收集期间用户线程暂停 CMS收集器:        描述:  它是一个以减少垃圾收集停顿时间为目标的收集器。由于运行阶段用户线程依然运行,所以需要预留足够的空间给用户线程使用。JDK1.5当老年代空间使用达到68%后会触发一下GC,JDK1.6中启动阀值调到92%, 若CMS运行期间预留的空间不足以满足程序使用就会出现一次"Concurrent Mode Failure"失败, 这时候会启动后备预案即临时启动Serial Old收集器重新进行老年代的垃圾收集,停顿时间会很长(Serial Old运行,用户线程暂停),因此-XX:CMSInitiatingOccupancyFraction设置过高的话容易导致大量"Concurrent Mode Failure"失败,性能反而下降。 CMS采用的是"标记清除算法",运行过程分为4个阶段:     ①.初始标记:标记GC Roots能直接关联的对象,此阶段速度快,; 需要暂停用户线程。     ②.并发标记:同时开启GC和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以GC线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。     ③.重新标记:修正并发标记阶段因用户线程继续运行而导致标记状态产生变化的那一部分标记记录,停顿时间比初始标记阶段稍长,远比并发标记阶段时间短; 需要暂停用户线程。     ④.并发清除:开启用户线程,同时GC线程开始对为标记的区域做清扫。 优势: 并发收集,低停顿 不足:  <1>.对CPU资源敏感(占用一部分线程会导致吞吐量下降);<2>.会造成内存碎片(碎片太多,在分配大的对象时会导致因为无法找到足够大的连续的空间从而不得不提前触发一次Full GC;  可以通过设置-XX:+UseCMSCompactAtFullCollection参数在CMS顶不住要进行Full GC时进行内存碎片整合,默认开启, 整理的阶段是不能并发执行的,虽然解决了内存碎片的问题,但会带来GC停顿时间变长的问题,可以通过-XX:CMSFullGCsBeforeCompaction参数设置执行多少次不压缩的Full GC后进行一次压缩GC,默认为0,表示每次Full GC都要进行碎片整理); <3>.无法清除"浮动垃圾"(因为清除阶段,用户线程依然在运行所以就会产生新的垃圾,这些垃圾出现在标记阶段之后,只有下一次GC才会被清理,这类垃圾被称为浮动垃圾)。 G1收集器:         描述:  同样是一个以降低收集停顿时间为目的的收集器, G1 GC是Jdk7的新特性之一、Jdk7+版本都可以自主配置G1作为JVM GC选项;作为JVM GC算法的一次重大升级、JDK7u后G1已相对稳定、且未来计划替代CMS、采用"标记整理算法"。G1将内存化整为零,把堆空间划分成了互相独立的区块。且每类区域空间可以是不连续的,当并发后台线程寻找可回收的对象时、有些区块包含可回收的对象要比其他区块多很多。虽然在清理这些区块时G1仍然需要暂停应用线程、但可以用相对较少的时间优先回收包含垃圾最多区块。这也是为什么G1命名为Garbage First的原因:第一时间处理垃圾最多的区块。         优势:  <1>.不会造成内存碎片;                 <2>.低停顿;                 <3>.不需要与其他收集器配合使用。                 <4>.Eden, Survivor, Old区不再固定、在内存使用效率上来说更灵活                 <5>.G1在回收内存后会马上同时做合并空闲内存的工作

---------------------

常用参数:
代码语言:javascript
复制
 UseSerialGC

 虚拟机运行在Client 模式下的默认值,打开此开关后,使用Serial +
Serial Old 的收集器组合进行内存回收

 UseParNewGC

 打开此开关后,使用ParNew + Serial Old 的收集器组合进行内存回收

 UseConcMarkSweepGC

 打开此开关后,使用ParNew + CMS + Serial Old 的收集器组合进行内存
回收。Serial Old 收集器将作为CMS 收集器出现Concurrent Mode Failure失败后的后备收集器使用

 UseParallelGC

 虚拟机运行在Server 模式下的默认值,打开此开关后,使用Parallel
Scavenge + Serial Old(PS MarkSweep)的收集器组合进行内存回收

 UseParallelOldGC

 打开此开关后,使用Parallel Scavenge + Parallel Old 的收集器组合进行内存回收

 SurvivorRatio

 新生代中Eden 区域与Survivor 区域的容量比值, 默认为8, 代表
Eden :Survivor=8∶1

 PretenureSizeThreshold

 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象
将直接在老年代分配

 MaxTenuringThreshold

 晋升到老年代的对象年龄。每个对象在坚持过一次Minor GC 之后,年
龄就加1,当超过这个参数值时就进入老年代

 UseAdaptiveSizePolicy

 动态调整Java 堆中各个区域的大小以及进入老年代的年龄

 HandlePromotionFailure

 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个
Eden 和Survivor 区的所有对象都存活的极端情况

 ParallelGCThreads

 设置并行GC 时进行内存回收的线程数

 GCTimeRatio

 GC 时间占总时间的比率,默认值为99,即允许1% 的GC 时间。仅在
使用Parallel Scavenge 收集器时生效

 MaxGCPauseMillis

 设置GC 的最大停顿时间。仅在使用Parallel Scavenge 收集器时生效

 CMSInitiatingOccupancyFraction

 设置CMS 收集器在老年代空间被使用多少后触发垃圾收集。默认值为
68%,仅在使用CMS 收集器时生效

 UseCMSCompactAtFullCollection

 设置CMS 收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅
在使用CMS 收集器时生效

 CMSFullGCsBeforeCompaction

 设置CMS 收集器在进行若干次垃圾收集后再启动一次内存碎片整理。
仅在使用CMS 收集器时生效
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 再谈引用:
  • 常用参数:
相关产品与服务
应用性能监控
应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档