Java虚拟机基本结构的简单记忆

Java堆:通常是放置实例化的对象的地方,堆分新生代和老年代空间,不断未被回收的对象越老,被放入老年代空间。分配最大堆空间:-Xmx     分配初始堆空间:-Xms,分配新生代空间:-Xmn,新生代的大小通常为整个堆空间的1/3到1/4。新生代通常分为eden和survivor(from,to)区。新生代被GC15(配置参数-XX:MaxTenuringThreshold,默认15)次后仍存活,进入老年代,但也可能提早晋升,由survivor区决定。新生代和老年代都属于JVM的Heap区,另外还有一个持久代Perm区,又叫永久区,是一块线程共享的内存区域,大小决定了系统能够保存多少个类,定义太多的类,会抛出内存溢出错误。分配永久区空间:-XX:PermSize和-XX:MaxPermSize(默认为64M)。算法

Java栈:放置对象的方法函数的地方,全部的方法的内部变量在Java栈中,之后进先出的方式不断进栈出栈,出栈即被销毁。对于彻底不会被其余线程访问的对象,能够分配在栈上,而不是分配在堆上,当方法结束后便自行销毁。分配栈空间:-Xss缓存

JVM垃圾回收的几种方法:多线程

一、标记清除法,标记全部从根节点开始的可达对象,未被标记的对象就是未被引用的垃圾对象,标记清除算法可能产生的最大问题就是空间碎片。标记操做完成后,系统回收全部不可达的空间。并发

二、复制算法。将原有的内存空间分为两块,每次只使用其中一块,经过标记清除法后,将存活对象复制到另外一块内存空间,并保持连续,没有空间碎片。而后清空原内存空间。主要用在新生代的垃圾回收中,由于在新生代,垃圾对象一般会多于存活对象。函数

三、标记压缩法。在标记清除法的基础上,再进行一次碎片整理。使得没有空间碎片,一般用于老年代。性能

四、分代算法。根据新生代和老年代的不一样,分别使用以上算法。另外为了高效回收新生代,在老年代的扫描中一般使用卡表。卡表用来表示老年代的某一区域中的全部对象是否持有新生代对象的引用,在新生代GC时能够不用花大量时间扫描全部老年代对象,只有卡表的标记为1时,才扫描给定区域的老年代对象,卡表为0则不扫描。线程

五、分区算法。将整个堆空间划分红连续的不一样小空间,每一个小空间都独立使用,独立回收。在相同条件下,堆空间越大,一次GC所须要的时间越长,从而产生的停顿也越长,为了更好的控制GC的停顿时间,每次合理地回收若干小区间,而不是整个堆空间,从而减小一次GC所产生的停顿。日志

垃圾收集器的种类(如下凡是只指定新生代的,老年代都是使用串行回收器)对象

一、串行回收器。单线程,独占式。串行回收时,全部线程都须要暂停。使用-XX:+UseSerialGC,表示新生代和老年代都使用串行回收器,新生代是复制,老年代是标记压缩。新生代日志标记DefNew,老年代日志标记Full GC.内存

2.一、并行回收器。ParNew回收器,新生代的垃圾收集器。简单将串行回收器多线程化,独占式。在并发能力比较强的CPU上,产生的停顿时间短于串行回收器。使用-XX:+UseParNewGC。线程数量使用-XX:ParallelGCThreads指定。最好与CPU数量至关,CPU数量小于8时,值为CPU数量,大于8时,值为3+((5*CPU_Count)/8)。日志标记ParNew。-XX:PretenureSizeThreshold设置对象直接晋升老年代的阈值,只对以上两种回收器有效。

2.二、并行回收器。新生代ParallelGC回收器,很是关注系统吞吐量。使用-XX:+UseParallelGC。控制系统吞吐量的两个重要参数,-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间,值大于0的整数,工做时会调整Java堆大小,若是值设的很小,JVM会使用较小的堆,致使垃圾收集变的很频繁。-XX:GCTimeRatio:设置吞吐量大小。值0到100之间的整数。值为n时,系统花费不超过1/(1+n)的时间用于垃圾收集。-XX:+UseAdaptiveSizePolicy能够打开自适应GC策略,自动调整eden,survivior的比例,晋升老年代的对象年龄等。以达到在堆大小,吞吐量和停顿时间之间的平衡点。手工调困难场合下使用,指定最大堆-Xmx,目标吞吐量-XX:GCTimeRatio,停顿时间-XX:MaxGCPauseMillis,让JVM自动调优。日志标记,PSYoungGen.注:吞吐量和吞吐时间是互相矛盾的,减小停顿时间会减小系统吞吐量,增长吞吐量会增长最大停顿。

2.三、并行回收器。老年代ParallelOldGC回收器。使用-XX:+UseParallelOldGC,新生代则会使用ParallelGC回收器。-XX:ParallelGCThreads设置线程数量。日志标志Full GC[PSYoungGen].

三、CMS回收器:标记型多线程回收器,通常工做在老年代,新生代使用ParNew回收器。分初始标记,并发标记,预清理,从新标记,并发清理,并发重置几个阶段,其中初始标记跟从新标记是系统独占的。预清理是并发的(垃圾回收线程跟应用线程同时进行),能够关闭开关-XX:-CMSPrecleaningEnabled,不进行预清理。启用CMS回收器的参数:-XX:+UseConcMarkSweepGC。默认并发线程数(ParallelGCThreads+3)/4,ParallelGCThreads表示GC并行(应用程序中止,同时多个线程一块儿执行GC)时使用的线程数量。并发线程数量也能够经过-XX:ConcGCThreads或者-XX:ParallelCMSThreads参数设置。由于CMS整体不是独占的,在回收过程当中,应用程序依然会产生垃圾,因此当堆内存达到必定阈值是开始回收,该阈值可使用-XX:CMSInitiatingOccupancyFraction来设置,默认是68。调优方法,当内存增加缓慢,增大阈值,下降CMS触发频率,当内存增加很快,下降阈值,避免频繁触发老年代串行收集器(老年代收集时,应用程序将彻底中止,停顿时间较长)。-XX:+UseCMSCompactAtFullCollection开关可使CMS在垃圾收集完成后进行一次碎片整理。-XX:CMSFullGCsBeforeCompaction参数能够设置多少次CMS回收后,进行一次碎片整理。日志标记:初始标记[CMS-initial-mark],开始并发标记 [CMS-concurrent-mark-start],开始并发结束标记 [CMS-concurrent-mark],预清理标记 [CMS-concurrent-preclean-start] ,预清理标记费时 [CMS-concurrent-preclean: 0.017/0.018 secs] ,预清理开始[CMS-concurrent-abortable-preclean-start],预清理结束费时[CMS-concurrent-abortable-preclean: 0.011/0.014 secs],从新标记[CMS-remark],开始并发清理 [CMS-concurrent-sweep-start] ,并发重置 [CMS-concurrent-reset-start] 。CMS回收器是一个关注停顿的垃圾收集器。若是要回收Perm(永久区),须要打开-XX:+CMSClassUnloadingEnabled开关。

四、G1回收器,分代分区回收器,实现了分代分区算法。可使用-XX:+UseG1GC标记打开G1收集器开关。回收过程有4个阶段。一、新生代GC.二、并发标记周期.三、混合收集.四、若是须要,可能会进行Full GC。新生代GC的主要工做时回收eden区和survivor区,一旦eden区被占满,就会启动,清空eden区,并复制到survivor区,因此GC一次,eden区变0,survivor增大。日志标记[GC pause (young)]。并发标记阶段跟CMS相似,分初始标记,根区域扫描,并发标记,从新标记,独占清理,并发清理。并发标记周期并不清理大量垃圾,只是标记了一些含有大量垃圾的G区域,交给混合收集去清理。混合收集阶段会清理标记为G的区域,并把存活的对象移动到其余区域。日志标记[GC pause (mixed)]。必要时的Full GC,由于应用程序跟GC线程交替工做,不免出现内存不足,这种状况时会产生一次Full GC.目标最大停顿时间参数-XX:MaxGCPauseMillis,若是设的太短,新生代GC次数会增长,老年代在混合收集时,会减小收集的区域数量,从而增长了Full GC的可能性。并行回收时,工做线程数量参数-XX:ParallelGCThreads。-XX:InitiatingHeapOccupancyPercent参数指定堆使用率多少时,触发并发标记周期的执行,默认为45,即整个堆占用率达到45%时,执行并发标记周期。设置过大会致使并发周期迟迟不启动,引发Full GC的可能性增大。太小会使得并发周期很是频繁,大量GC线程抢占CPU,致使应用程序的性能降低。

五、TLAB,线程本地分配缓存,线程专属分配对象区间,避免多线程冲突。自己占用eden区的空间。开启为-XX:+UseTLAB(关闭为-UseTLAB)。使用-XX:TLABSize指定一个TLAB的大小,-XX:-ResizeTLAB禁用从新分配大小。当分配的对象大于TLAB剩余空间时,由-XX:TLABRefillWasteFraction来设置一个阈值,假如为n(默认值为64),表示为1/n的空间大小,当对象大小大于1/n时,分配在堆上,若是小于,则废弃该TLAB,新建TLAB来分配该对象。日志,desired_size为TLAB大小,slow allocs上一次新生代GC到如今为止慢分配(对象直接分配到堆上)次数,refill waste分配阈值,alloc当前线程的TLAB分配比例和使用评估量,refills表示该线程的TLAB空间被从新分配并填充的次数,waste表示空间的浪费比例。TLAB totals中,thrds相关线程总数,refills全部线程refills的总数,其后的max表示refills次数最多的线程的refills次数。

最后说一下new一个对象的过程,先栈上分配(通常在方法中)(不成功)->TLAB分配(不成功)->eden分配(或者老年代分配,根据对象大小)。

相关文章
相关标签/搜索