热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JVM随笔分类(JVM堆的内存回收)

2019独角兽企业重金招聘Python工程师标准JVM常用的回收算法是:标记清除算法标记复制算法标记整理算法其中上诉三种算法都先

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

  JVM常用的回收算法是:
  
  标记/清除算法
  
  标记/复制算法
  
  标记/整理算法
  
  其中上诉三种算法都先具备,标记阶段,通过标记阶段,得到当前存活的对象,然后再将非标记的对象进行清除,而对象内存中对象的标记过程,则是使用的
  
  “根搜索算法”,通过遍历整个堆中的GC ROOTS,将所有可到达的对象标记为存活的对象的一种方式,则是 “根搜索算法”,其中根是指的“GC ROOTS”,在JAVA中,充当GC ROOTS的对象分别有:“虚拟机栈中的引用对象”,“方法区中的类静态属性引用的对象”,“方法区中的常量引用对象”,“本地方法栈中JNI的引用对象”,凡是于上述对象存在可到达对象时,则该对象将标记为可存活对象,否则则为不可达对象,即可回收对象。在根搜索算法之前,还存在一个“引用计数算法”,即根据对象的被引用次数来进行计算,凡是对象的引用次数为0时,则表示为可回收对象,但对于互相引用的对象,如果不手动将互相引用的对象置空时,则该对象的引用次数永远将不会为0,则永久不会回收,则必然是错误,可参考:https://www.cnblogs.com/zuoxiaolong/p/jvm3.html
  
  根据上述所提到的算法,可知:“根搜索算法”解决了标记那些对象是可回收,那些是不可回收对象的一个作用,但是对于具体在标记后的,回收行为,则是上述前三个算法的具体应用了,分别是“标记后清除”,以及“标记后复制”,及“标记后整理”,
  
  “标记清除算法”的优势以及劣势:由于标记清除算法只需要两种动作行为,分别是:1.通过根搜索算法,标记可到达的存活对象,2.清除不可到达的对象内存;通过使用前面的两步,则将对应的不可达内存对象,进行了快速的清理,但是对于被回收后剩余的空闲内存的空间则是不连续的,因为被回收对象都是随机存在于内存的各个角落,在被回收后,内存的空间自然是存活的对象各自占据在各自原有的对象内存位置中,而并没有将剩余的存活对象进行相关的内存空间的整理,所以对于后续 分配数组对象时,寻找一个连续的内存空间则是一个较为麻烦的事情,。故:"标记/清除"的优势则是,内存空间的整理快速,效率较高,但劣势则是:对应的清理后空间则是不连续的内存空间。
  
  “标记/复制算法”:通过维护一份空闲内存的方式,来进行对象的回收,如:当前内存分为两份,分别为活动内存T1和非活动内存T2,在使用中时使用活动内存,当活动内存满的时候,进行 对象的标记,得到当前的存活对象,此时将对应的存活对象,复制到对应的非活动内存T2当中,且严格按照对象内存地址进行依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址; 对象复制的同时T1内存中的对象全部进行清除,此时的T2则扮演着活动内存的角色,而T1则是非活动内存,通过上述可知,使用复制算法的方式避免了“标记/清除”算法对于空间连续性的弊端,但复制算法的劣势则是,一直保留着一份空闲的内存,作为对应的备用内存,这整整浪费了一半的内存,相对来时还是比较浪费的。
  
  “标记/整理算法”:1. 标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GC Roots,然后将存活的对象标记。2.  移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段才称为整理阶段。 可以看出标记整理算法,是通过标记所有的存活对象,然后再严格按照内存地址移动对应的存活对象后,再将末端的内存地址全部回收的方式,来进行的内存的空间整理,,所以,标记整理算法,并非是单单的:标记/清除/整理的方式,而是通过整理存活对象的连续性地址后,再进行末端地址回收的方式进行的内存的整理。;通过上述也可以看出 标记整理算法,弥补了标记清除对于不连续空间的内存整理的特性,也避免了复制算法对于一半空闲内存的浪费的特性。尽管标记整理拥有较好的特性,但没有特别完美的算法,所以,在劣势上:标记整理算法的整体执行效率是要低于标记复制算法的。
  
  此处想要说明一下:JVM对于内存的清理上来看:标记整理算法,分别是先通过扫描GC ROOT得到存活对象,然后 移动对应的存活对象的地址,使其进行以此排列,然后将 依次进行排列的内存地址,往后的所有的末端内存,直接进行回收 的方式来进行具体的操作的。所以,“标记整理算法”实际上的操作方式可以分为三步,分别是:1. 标记 2. 移动对象所在内存地址,3.  将末尾内存直接全部清除。而,“复制算法”则是:1. 标记存活对象,2. 移动存活对象所在地址,将其移动到空闲内存中即可。相同操作的情况下,可以看出:复制算法的效率是大于标记整理算法的。毕竟整理算法除了和复制算法都操作了具体的内存地址的移动以外,还比复制算法多出了一个末尾清除的步骤,所以:复制算法的效率>整理算法,,而“标记清除算法”,1. 标记所有存活对象,2. 清除所有“不连续的”空间内存。通过对比一些时间复杂度和执行效率上来看,JVM对于不连续的内存空间的清理的执行时间,似乎是要大于整理算法直接将末尾内存直接清除的执行时间的,所以简单的去看执行效率和时间复杂度上来看:标记复制算法>标记整理算法>标记清除算法(也可能是由于标记清除算法是比较老的算法的缘故,导致标记清除算法的执行效率对于其余的两种算法,但实际情况则不见得一定是这样,此处的效率只是简单的对比了时间复杂度来看,实际情况lz总还是觉得标记清除算法的执行时间和效率是大于整理算法的,毕竟单单从执行步骤来看,标记清除算法的执行是占据优势的,除非jvm对于非连续内存的清除方式真的是过于较低而导致,此处先做一下简单的记录罢了)
  
  最终的算法,分代收集算法,通过将jvm的内存区域进行划分所进行执行的一直算法方式:
  
  JVM中运行时内存区域分别有:堆,栈,本地栈,方法区,寄存器;其中栈和寄存器指针,是线程执行时的私有内存,线程结束后则栈内存同步释放, 所以JVM的内存回收,则共需关注的是堆以及方法区的内存回收,其中堆是各个对象创建时的内存区域,而方法区则包含类的calss以及常量,静态资源所对应的各个内存的存储区域。所以集中在堆中的不存活对象以及方法区的对象的回收,便是整体GC内存回收时的重点,;
  
  “分代收集算法”:JVM中将堆划分为不同的区域,分别是 新生代,老年代,以及永久代,根据对象的声明周期不同,所以针对不同生命周期的对象的回收方式也不同,以此来增加回收效率。
  
  在Java堆中:大多数对象是在新生代中被创建,当新生代中的对象在经历过多次Minor GC后,且仍然为存活对象的数据,则将会晋升到老年代,(其中包含了晋升阀值和JVM自动调节晋升阀值的一个概念),当简单了接了上述概念后,则已经基本了接了新生代以及老年代的作用,下面详细进行下相关的介绍:
  
  在Java中,新创建的对象数据则都是在新生代中进行创建,一般表现特征为生命周期较短,通过新生代的垃圾回收后只要少量的对象存活,所以新生代更加适合 执行效率较高的复制算法,针对复制算法的执行特征,所以要存在一份备用的内存区域来作为新生代在内存回收后的临时对象的存储场地,于是 新生代中便又划分为了对应的内存区域分别为:Eden区,以及 两个 Survivor区域,其中Eden区域的内存特征和新生代最初的内存特征不变,是用于存放对象在初始创建时的内存区域,当Eden区中的新生代对象占满了对应的Eden区域内存空间时,便会发生对应的Minor GC,即对应的内存回收,由于Eden 区域中的对象生命周期普遍较短,在经历第一次的Minor GC后,则将对应的存活对象,移动到对应的Survivor区域,其中两个Survivor区域中,选择任意一个,作为存活对象的新的存储空间,所以此处由此可知,Survivor作为Eden GC后的备用仓库,Survivor的大小设置只需要可以存储下Eden区的存活对象即可,一般推荐,Survivor区域的内存大小占整个年轻代的1/6即可,即:-XX:SuvrivorRatio=4,当然,所有的内存值的设置,都可以在后续根据项目的具体情况进行对应的GC的优化,当第一个from Survivor区域空间满时,则将会把对应的对象转移到对应的to Survivor中,然后清空对应的from Survivor区域,然后依次进行复制算法的循环,在对象不断的从From Suvrivor转移到to Survivor以及从to Survivor转移到from Suivivor的同时,Survivor的作用除了是Eden区的备用仓库外,还具备筛选“老对象”的作用,当Survivor中的对象在经历过多次的Minor GC时,还没有被清除时,则便可以晋升为“老年代”,老年代一般用于存储存活时间更长的对象数据,而如何识别对象具备晋升为“老年代”的数值,则可以通过MaxTenuringThrehold进行设置,默认阀值为15,即年轻代中的对象在经历过15次的Minor GC还存在于对象空间的数据,则可以晋升到年老代,,,,但:如果年轻代的对象数据不断增长,而Survivor区域的对象还迟迟不满足MaxTenuringThrehold所设置的晋升阀值,此时一旦Survivor内存溢出,则无论对象的年龄阀值是多大,则都会全部晋升到年老代中,这对于年老代来说是个噩梦,因为这将导致不断的Full GC,且会不断降低程序的执行性能,,,,所以为了不存在MaxTenuringThrehold设置过大,而导致的晋升失败的情况,JVM则引入了动态的年龄计算,当累计的某个年龄大小的对象,超过了Survivor的一半时,则取当前的对象年龄作为新的对象晋升阀值,可参考:https://mp.weixin.qq.com/s/t1Cx1n6irN1RWG8HQyHU2w
  
  上面简单介绍了下相关的年轻代的回收的一些知识和问题后,后面陆续再分析下当前常用的GC的收集器分别有哪些:,以及各收集器的作用和各个参数的调节及注意事项等。
  
  关于GC收集器的更多简介可以参考该链接:https://www.cnblogs.com/zuoxiaolong/p/jvm8.html
  
  首先;常用的收集器分别是:串行,并行,并发 收集器,其中串行一般用于Cliend模式,即当前代码开发过程调试过程时所设置的模式,串行收集器分别包含:Serial Garbage Collector 串行年轻代收集器(复制算法),和 Serial Old Garbage Collector 串行老年代收集器(标记/整理算法),
  
  而并行收集器:则包括:ParNew Garbage Collector ,Paraller Scavenge,这两个是专门为年轻代设计的并行收集器,皆为复制算法,其中Paraller Scavenge则是-Server模式下的默认年轻代收集器,除此之外,并行收集器还剩余:Paraller Old,此收集器是老年代的并行收集器为 标记/整理算法,也是-Server模式下的默认老年代收集器。
  
  唯一的一个并发收集器:是专门用于年老代回收时的并发收集器:concurrent mark sweep(简称CMS),真正做到了GC程序和应用程序并发执行,不会暂停应用的执行程序的一款收集器。(所使用的执行算法为:标记/清除算法)。
  
  ---------------------------- 注:所有的GC收集器在执行过程当中,都会暂停应用线程,只是一般年轻代使用并行收集器的GC,由于并行执行,则应用的停顿时间则相对较短,所以感受不到对应的应用暂停的特征,但其实的确是先暂停对应的应用线程在GC执行过后,再唤醒对应的应用线程继续执行,可以通过查看GC日志,来查看当前GC时的实际耗费时间,。,,,,而CMS则是唯一一个,在GC收集时和应用程序线程同步进行的一款收集器,只是只适用于年老代的并发收集,,所以合适的收集器的组合,才可以出现更优的效果;,并且,在HotSport 中,除了CMS之外,其他的老年代收集器,在执行的过程中,都会同时收集整个GC堆,包括新生代,(此处是需要注意的)。
  
  合适的收集器的选择:
  
  对于对响应时间有较高的要求的系统,可以选择ParNew 作为新生代并行收集器,& CMS 作为对应的老年代收集器, 由于ParNew是并行收集,因此新生代的GC速度会非常快,停顿时间很短。而年老代的GC采用并发搜集,大部分垃圾搜集的时间里,GC线程都是与应用程序并发执行的,因此造成的停顿时间依然很短。
  
  对于对系统吞吐量有要求的系统,可选择Paraller Scavenge作为 年轻代的并行收集器,使用Paraller Old 作为年老代的并行收集器,由于年轻代和年老代都是使用并行收集器,所以对系统停顿时间较短,且Paraller Scavenge收集器可以更加精准的控制GC的停顿时间和吞吐量的设置,所以对于在单位时间对系统可完成的指令数(吞吐量)有要求,但是对系统的响应时间没有过大要求的系统可以使用上述的两种结合处理器;(要想在单位时间内处理的请求更多,即系统的吞吐量更高,则设置相关的年轻代的大小,可以有效的增加系统的吞吐量和处理时间。)
  
  JVM的可参考配置:
  
  ParNew & CMS:
  
  Paraller Scavenge & Paraller Old:
  
  假设当前项目所部属服务器内存为8G,且总活跃对象数据为1G(1G的活跃对象数据已经很大了),
  
  则当前总堆的对象数据设置为:(初始jvm默认内存设置与 总的JVM堆的可分配内存Xmx一致,可避免JVM GC后堆的重新分配);
  
  堆的大小设置:-Xms8192m,-Xmx8192m
  
  新生代的设置比例为:-Xmn1536m,
  
  老年代的设置比例为:-XX:NewRatio用于设置年轻代与年老代所占比例值,当上述新生代采用Xmn进行设置时,此处NewRatio可以不用设置,则默认为 总堆内存-新生代内存 = 老年代内存;
  
  永久代设置比例为:-XX:PermSize=1536m,-XX:MaxPermSize=1536m
  
  新生代中Eden与from to内存区的比例:-XX:SurvivorRatio=4,表示当前Eden区和两个From区的比值为:4:2,则当前eden区占整个年轻代的4/6;(说明一下:JVM中的动态年龄计算,则是根据对应的From区的大小和对象的年龄进行阀值的计算的)
  
  新生代对象晋升年龄阀值的设置:-XX:MaxTenuringThreshold=15,默认情况下对象的晋升年龄阀值为15,上面已经提到过了JVM则会根据新生代中幸存区Survivor(及From 和to区域)的大小以及幸存区中对象的年龄动态计算晋升阀值的数值,那么?是不是此处设置XX:MaxTenuringThreshold则无效了吗?错!,JVM在设置晋升阀值是根据所计算出的年龄值和XX:MaxTenuringThreshold的年龄值进行对比,那个值越小,则使用当前更小的年龄值作为新的晋升阀值,所以如果设置XX:MaxTenuringThreshold的值为0,或者更小的值1,2,等,则将更快的增加新生代进入老年代的频率,(举个例子,对于年老代比较多的应用可以直接将对象晋升到年老代,且由于CMS的年老代回收是只回收年老代且并发收集过程中不影响应用线程的运行,所以直接晋升年老代,对于GC的回收的时间和效率似乎也是个不错的选择,不过目前没有遇到过这种类似的情况的应用),
  
  单个线程所占用堆栈内存的大小设置:-Xss256k,用于表示当前每个线程在创建时所对应的线程栈的空间内存的大小,具体可详细看下 (书写)java虚拟机的内存区域分配(一个不断记录和推翻以及再记录的一个过程)该篇记录文章,此处主要是说明下Xss创建线程时所占用的内存为操作系统的内存,而并非堆的内存空间,所以在设置堆的内存大小时,也需要留存下对应的操作系统内存,处理分配给对应的操作系统的应用使用外,还应留存对应的线程内存,也需要设置对应的服务器当前应用进程可创建最大线程的参数设置,可参考所书写的该篇文章; (*******书写+csdn)由多线程内存溢出产生的实战分析 - CSDN博客
  
  以上,基本是一个默认在不配置GC收集器前对堆内存空间比例的基本设置,需要了接的是关于新生代中Eden和Suivivo的比例设置,在不进行配置的情况下JVM实际也是会给一个默认的自动参数配置的,并且以上关于JVM配置的比例参数皆是设置对JDK1.6的比例设置,所以对于永久代的设置并非是占用的整个堆的内存比例进行设置的,而是使用的操作系统的内存进行的相关永久代内存的设置,------
  
  ---- 设置对应的GC收集器的参数配置:
  
  ---- ParNewGC  + CMS 收集器的配置
  
  -XX:+UseParNewGC                    -XX:ParallelGCThreads=4
  
  设置开启ParNew收集器                设置当前并行收集器开启的线程数量:,参考对应的url(http://www.blogjava.net/paulwong/archive/2014/06/16/414812.html)
  
  -XX:+UseCMSCompactAtFullCollection      -XX:CMSFullGCsBeforeCompaction=0        -XX:CMSInitiatingOccupancyFraction=80                      -XX:+CMSScavengeBeforeRemark
  
  设置当前CMS后执行碎片整理                             设置多少次FULL GC后进行碎片整理                    表示老年代内存达到使用率的80%时,则进行CMS GC           设置每次CMS GC的Remark前执行下Minor GC
  
  (上述4个参数可参考URL:http://www.cnblogs.com/onmyway20xx/p/6605324.html)
  
  -XX:+UseConcMarkSweepGC                         -XX:ParallelCMSThreads=4                                           -XX:MaxDirectMemorySize=256M       -XX:+CMSParallelRemarkEnabled
  
  设置开启CMS 收集器                     CMS默认开启线程数设置(默认为(ParallelGCThreads+3)/4)             堆外内存的大小设置(如ByteBuffer字节缓存时,则占用的为堆外内存:查看链接:http://hellojava.info/?tag=maxdirectmemorysize ,https://blog.csdn.net/aesop_wubo/article/details/38406709)              -----  CMS在Remark执行前,会执行一个可中断的并发预清理(CMS-concurrent-abortable-preclean),默认为开启CMSParallelRemarkEnable,此处使用-XX:+CMSParallelRemarkEnabled显示开启,(注:CMS的Remark阶段是全量堆搜索(old+xmn)得到存活对象,详情可查看:美团文章的案例二:https://mp.weixin.qq.com/s/t1Cx1n6irN1RWG8HQyHU2w)
  
  此处设置-XX:CMSInitiatingOccupancyFraction=80 的原因为:1. 每次CMS GC后,都设置了清理内存碎片,CMSFullGCsBeforeCompaction=0,所以不存在 晋升对象没有连续的内存空间存储而引起的CMS GC并发清理失败的问题(CMS清理失败将会使用serial old来进行STW全局的FULL GC),2.每次CMS执行Remark阶段时已经提前执行了Minor GC,所以新生代空间满了以后的再次晋升一般不会特别快,第二,Remark阶段时的Minor GC,尽管可能会存在新生代的对象的晋升,但老年代剩余的20%比例,应该是足足可以存放下的,所以设置80%时触发CMS的GC一般是OK的,当然80%的该值,也可以通过每次Minor GC晋升对象的大小取其平均值得到对应的大小,然后留下相对较为充足的空间比例也是合适的,。
  
  另:关于JVM何时会触发STW的Full GC的机制可以查看:美团文章的第三个案例(https://mp.weixin.qq.com/s/t1Cx1n6irN1RWG8HQyHU2w)
  
  另外:Full GC 和CMS的GC是不同的,CMS 的GC是单纯的老年代GC,在GC日志中对应的标识为:CMS-inital-mak,CMS-concurrent-mark-start,等CMS的日志标识,
  
  可以查看该图片(https://mmbiz.qpic.cn/mmbiz_png/hEx03cFgUsV0a8RiaD6p2fV75LI7IdZVMia9ML0LccOY9bWeBvXzMbQnWaKmyhmWXDO1eU4U5X4YrvJdZpPE1pbQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1),除了CMS的GC外,其他的老年代GC在执行时好像是都同时执行的FULL GC,上面也有提到过,关于CMS执行时的四个阶段的特性和执行方式,也可以查看美团的文章的案例2,以及该文章中对GC收集器的介绍,其中包含CMS的收集器的简单介绍(https://www.cnblogs.com/zuoxiaolong/p/jvm8.html)
  
  -XX:+PrintTenuringDistribution 开启jvm对象晋升年龄的打印 Desired survivor size 107347968 bytes, new threshold 1 (max 30)
  
  可参考推荐GC为:
  
  -Xmn512M -Xms1024M -Xmx1024M -XX:MaxPermSize=250M -Xss256k -Xconcurrentio -XX:SurvivorRatio=4 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=15 -XX:MaxDirectMemorySize=256M -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSScavengeBeforeRemark -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider -Dsun.net.inetaddr.ttl=60 -Dorg.mortbay.jetty.Request.maxFormContentSize=-1 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/ftdq_kbase/ibot_core_8013/logs  -XX:+PrintGCDetails  -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/app/ftdq_kbase/ibot_core_8013/logs/gc.log
  
  -Xmn512M -Xms1024M -Xmx1024M -XX:MaxPermSize=250M -Xss256k -Xconcurrentio -XX:SurvivorRatio=4 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=15 -XX:MaxDirectMemorySize=256M -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSScavengeBeforeRemark -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider -Dsun.net.inetaddr.ttl=60 -Dorg.mortbay.jetty.Request.maxFormContentSize=-1 www.dfgjpt.com-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/ftdq_kbase/ibot_core_8013/logs www.thd178.com/ -XX:+PrintGCDetails -XX:+PrintTenuringDistribution -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/app/ftdq_kbase/ibot_core_8013/logs/gc.log  -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=22223
  
  JAVA_OPTIONS="-Xmn1000M -Xms3000M -Xmx3000M -XX:MaxPermSize=512M -Xss128k -Xconcurrentio -XX:SurvivorRatio=5 -XX:TargetSurvivorRatio=90 -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSParallelRemarkEnabled -XX:+CMSPermGenSweepingEnabled -XX:MaxTenuringThreshold=31 -XX:CMSInitiatingOccupancyFraction=90 -Xloggc:/opt/jetty_kbase-search-7661/logs/gc.log -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses www.tiaotiaoylzc.com-XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseConcMarkSweepGC -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider www.dfgjpt.com -Dsun.net.inetaddr.ttl=60 -Dorg.mortbay.jetty.Request.maxFormContentSize=-1 -Djava.rmi.server.hostname=172.16.9.55 -Dcom.sun.management.jmxremote.port=17661 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dsolr.solr.home=/opt/jetty_kbase-search-7661/solr_home/solr www.yongshi123.cn www.mhylpt.com -Dsolr.library.home=/opt/jetty_kbase-search-7661/solr_home"
  
  此处需要注意一点,第三个参数中为search参数,新增了 +ExplicitGCInvokesConcurrentAndUnloadsClasses 标识,(参考:https://blog.csdn.net/aesop_wubo/article/details/38406709)
  
  由于系统中使用-XX:MaxDirectMemorySize=256M(上面提到的堆外内存的设置,用于文件读取拷贝时增加效率),但是堆外内存的设置后,发现每隔一小时会进行一次Full GC,但此时FUll GC时,老年代根本没有用满,且永久代也没有用满(方太上便是这种情况,也是一个小时触发一次Full GC),根据上述的参考链接可知:触发Full GC的目的主要是想要回收 堆外内存的回收,即Native所使用内存的回收,但Young GC时,不具备回收堆外内存的情况,所以会主动触发Full GC进行内存回收,此处使用 ExplicitGCInvokesConcurrentAndUnloadsClasses  参数,可以将回收堆外内存的任务交给 CMS进行处理,CMS 的回收好处相比于Fulll GC的好处,此处则不再做累赘,通过使用CMS回收堆外内存的情况,则可以避免频繁的Full GC,(FUll GC 期间对系统是有影响的,且是STW的,所以对于使用CMS和Full GC进行回收堆外内存,此处也应该根据实际需调整,因为CMS 在并发预清理阶段也是STW的,不过合理的配置CMS,则回收时间应该也是最佳的),另外,提一下上述的一个问题,上述的 -XX:+CMSParallelRemarkEnabled 表示在CMS,Remark之前,进行一个可中断的并发预清理,(此处其实可以不开启,因为此处已经使用CMSScavengeBeforeRemark ,表示每次CMS前进行一次年轻代的回收,那么 此时则没有必要等待5秒或怎样的一个中断的预清理了,此处做已备注,可考虑测试去除等操作)
  
  并发收集的参数默认 -XX:UseAdaptiveSizePolicy的开启,将会全权管理内存分配,此时所设置的新生代的eden和survivor的比例配置将会失效,等,。
  
  CMS的设置,可以设置FUll GC前先进行下相关的Minor GC的回收,以及可以设置是否开启对永久代的回收,(因为如果应用中存在较多的动态类,或使用String.inten()等将数据都放置到了对应的常量池中,则对永久代Perm的回收则也是有必要的, )除此之外,可以参考美团,或者jvm参数设置中对CMS的一些配置的说明,也是较为清晰和详细的。
  
  对象每经历一次Minor GC,年龄加1,达到“晋升年龄阈值”后,被放到老年代,这个过程也称为“晋升”。显然,“晋升年龄阈值”的大小直接影响着对象在新生代中的停留时间,在Serial和ParNew GC两种回收器中,“晋升年龄阈值”通过参数MaxTenuringThreshold设定,默认值为15。


转:https://my.oschina.net/u/3386278/blog/3019995



推荐阅读
  • 在Hive中合理配置Map和Reduce任务的数量对于优化不同场景下的性能至关重要。本文探讨了如何控制Hive任务中的Map数量,分析了当输入数据超过128MB时是否会自动拆分,以及Map数量是否越多越好的问题。通过实际案例和实验数据,本文提供了具体的配置建议,帮助用户在不同场景下实现最佳性能。 ... [详细]
  • 本文深入探讨了 MXOTDLL.dll 在 C# 环境中的应用与优化策略。针对近期公司从某生物技术供应商采购的指纹识别设备,该设备提供的 DLL 文件是用 C 语言编写的。为了更好地集成到现有的 C# 系统中,我们对原生的 C 语言 DLL 进行了封装,并利用 C# 的互操作性功能实现了高效调用。此外,文章还详细分析了在实际应用中可能遇到的性能瓶颈,并提出了一系列优化措施,以确保系统的稳定性和高效运行。 ... [详细]
  • 在CentOS上部署和配置FreeSWITCH
    在CentOS系统上部署和配置FreeSWITCH的过程涉及多个步骤。本文详细介绍了从源代码安装FreeSWITCH的方法,包括必要的依赖项安装、编译和配置过程。此外,还提供了常见的配置选项和故障排除技巧,帮助用户顺利完成部署并确保系统的稳定运行。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 本题库精选了Java核心知识点的练习题,旨在帮助学习者巩固和检验对Java理论基础的掌握。其中,选择题部分涵盖了访问控制权限等关键概念,例如,Java语言中仅允许子类或同一包内的类访问的访问权限为protected。此外,题库还包括其他重要知识点,如异常处理、多线程、集合框架等,全面覆盖Java编程的核心内容。 ... [详细]
  • HBase在金融大数据迁移中的应用与挑战
    随着最后一台设备的下线,标志着超过10PB的HBase数据迁移项目顺利完成。目前,新的集群已在新机房稳定运行超过两个月,监控数据显示,新集群的查询响应时间显著降低,系统稳定性大幅提升。此外,数据消费的波动也变得更加平滑,整体性能得到了显著优化。 ... [详细]
  • 深入解析:使用C++实现Python字节数组(struct)的高效处理方法 ... [详细]
  • ESP32 IRAM 内存优化策略与实践总结
    本文总结了针对ESP32 IRAM内存溢出问题的优化策略与实践经验。通过详细分析ESP32的内存结构和IRAM分配机制,提出了一系列有效的解决方案,包括代码优化、内存管理技巧和编译器配置调整,旨在帮助开发者有效解决`.espressif/tools/xtensa-esp32-elf/esp-2`等类似错误,提升系统性能和稳定性。 ... [详细]
  • 全面解析Java虚拟机:内存模型深度剖析 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • 通过整合JavaFX与Swing,我们成功地将现有的Swing应用程序组件进行了现代化改造。此次升级不仅提升了用户界面的美观性和交互性,还确保了与原有Swing应用程序的无缝集成,为开发高质量的Java桌面应用提供了坚实的基础。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • Linux磁盘管理入门指南:MBR分区格式详解与安装步骤
    在 CentOS 7.x 环境下,本文详细介绍了 MBR 分区格式的基本概念及其安装步骤。实验中使用了 SAS 和 SATA 硬盘,其中 SAS 硬盘主要用于企业级应用和服务器,而 SATA 硬盘则广泛应用于个人计算机和低端服务器。文章通过具体操作示例,帮助读者更好地理解和掌握 Linux 磁盘管理的基本技能。 ... [详细]
  • 在高清节目的高比特率传输过程中,使用外接USB硬盘进行时间平移(timeshift)时,出现了性能不足和流数据丢失的问题。通过深入研究,我们发现通过对图像组(GOP)和图像头(I-frame)的精确定位技术进行优化,可以显著提升系统的性能和稳定性。本研究提出了改进的图像组与图像头定位算法,有效减少了数据丢失,提高了流媒体传输的效率和质量。 ... [详细]
author-avatar
书友16941424_529
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有