前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java虚拟机基本结构的简单记忆 顶

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

作者头像
算法之名
发布2019-08-20 11:08:21
3970
发布2019-08-20 11:08:21
举报
文章被收录于专栏:算法之名算法之名

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垃圾回收的几种方法:

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

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

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

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

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

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

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

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

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

3、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开关。

4、G1回收器,分代分区回收器,实现了分代分区算法。可以使用-XX:+UseG1GC标记打开G1收集器开关。回收过程有4个阶段。1、新生代GC.2、并发标记周期.3、混合收集.4、如果需要,可能会进行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,导致应用程序的性能下降。

5、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分配(或者老年代分配,根据对象大小)。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档