优秀网站设计作品分析,阳春做网站公司,做黄图网站接广告好赚吗,创新的南昌网站设计1、有哪几种垃圾回收器#xff0c;各自的优缺点是什么#xff1f;
垃圾回收器主要分为以下几种#xff1a;Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1#xff1b; Serial:单线程的收集器#xff0c;收集垃圾时#xff0c;必须stop the worl…1、有哪几种垃圾回收器各自的优缺点是什么
垃圾回收器主要分为以下几种Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1 Serial:单线程的收集器收集垃圾时必须stop the world使用复制算法。它的最大特点是在进行垃圾回收时需要对所有正在执行的线程暂停stop the world对于有些应用是难以接受的但是如果应用的实时性要求不是那么高只要停顿的时间控制在N毫秒之内大多数应用还是可以接受的是client级别的默认GC方式。 ParNew:Serial收集器的多线程版本也需要stop the world复制算 Parallel Scavenge:新生代收集器复制算法的收集器并发的多线程收集器目标是达到一个可控的吞吐量和ParNew的最大区别是GC自动调节策略虚拟机会根据系统的运行状态收集性能监控信息动态设置这些参数以提供最优停顿时间和最高的吞吐量 Serial Old:Serial收集器的老年代版本单线程收集器使用标记整理算法。 Parallel Old是Parallel Scavenge收集器的老年代版本使用多线程标记-整理算法。 CMS:是一种以获得最短回收停顿时间为目标的收集器标记清除算法运作过程初始标记并发标记重新标记并发清除收集结束会产生大量空间碎片 G1:标记整理算法实现运作流程主要包括以下初始标记并发标记最终标记筛选回收。不会产生空间碎片可以精确地控制停顿G1将整个堆分为大小相等的多个Region区域G1跟踪每个区域的垃圾大小在后台维护一个优先级列表每次根据允许的收集时间优先回收价值最大的区域已达到在有限时间内获取尽可能高的回收效率
垃圾回收器间的配合使用图
各个垃圾回收器对比
2、详细说一下CMS的回收过程CMS的问题是什么
CMS(Concurrent Mark Sweep并发标记清除) 收集器是以获取最短回收停顿时间为目标的收集器追求低停顿它在垃圾收集时使得用户线程和 GC 线程并发执行因此在垃圾收集过程中用户也不会感到明显的卡顿。
从名字就可以知道CMS是基于“标记-清除”算法实现的。CMS 回收过程分为以下四步 初始标记 CMS initial mark)主要是标记 GC Root 开始的下级注仅下一级对象这个过程会 STW但是跟 GC Root 直接关联的下级对象不会很多因此这个过程其实很快。 并发标记 (CMS concurrent mark)根据上一步的结果继续向下标识所有关联的对象直到这条链上的最尽头。这个过程是多线程的虽然耗时理论上会比较长但是其它工作线程并不会阻塞没有 STW。 重新标记CMS remark顾名思义就是要再标记一次。为啥还要再标记一次因为第 2 步并没有阻塞其它工作线程其它线程在标识过程中很有可能会产生新的垃圾。 并发清除CMS concurrent sweep清除阶段是清理删除掉标记阶段判断的已经死亡的对象由于不需要移动存活对象所以这个阶段也是可以与用户线程同时并发进行的。
CMS 的问题 并发回收导致CPU资源紧张 在并发阶段它虽然不会导致用户线程停顿但却会因为占用了一部分线程而导致应用程序变慢降低程序总吞吐量。CMS默认启动的回收线程数是CPU核数 3/ 4当CPU核数不足四个时CMS对用户程序的影响就可能变得很大。 无法清理浮动垃圾 在CMS的并发标记和并发清理阶段用户线程还在继续运行就还会伴随有新的垃圾对象不断产生但这一部分垃圾对象是出现在标记过程结束以后CMS无法在当次收集中处理掉它们只好留到下一次垃圾收集时再清理掉。这一部分垃圾称为“浮动垃圾”。 并发失败Concurrent Mode Failure 由于在垃圾回收阶段用户线程还在并发运行那就还需要预留足够的内存空间提供给用户线程使用因此CMS不能像其他回收器那样等到老年代几乎完全被填满了再进行回收必须预留一部分空间供并发回收时的程序运行使用。默认情况下当老年代使用了 92% 的空间后就会触发 CMS 垃圾回收这个值可以通过 -XX:CMSInitiatingOccupancyFraction 参数来设置。 这里会有一个风险要是CMS运行期间预留的内存无法满足程序分配新对象的需要就会出现一次“并发失败”Concurrent Mode Failure这时候虚拟机将不得不启动后备预案Stop The World临时启用 Serial Old 来重新进行老年代的垃圾回收这样一来停顿时间就很长了。 内存碎片问题 CMS是一款基于“标记-清除”算法实现的回收器这意味着回收结束时会有内存碎片产生。内存碎片过多时将会给大对象分配带来麻烦往往会出现老年代还有很多剩余空间但就是无法找到足够大的连续空间来分配当前对象而不得不提前触发一次 Full GC 的情况。 为了解决这个问题CMS收集器提供了一个 -XX:UseCMSCompactAtFullCollection 开关参数默认开启用于在 Full GC 时开启内存碎片的合并整理过程由于这个内存整理必须移动存活对象是无法并发的这样停顿时间就会变长。还有另外一个参数 -XX:CMSFullGCsBeforeCompaction这个参数的作用是要求CMS在执行过若干次不整理空间的 Full GC 之后下一次进入 Full GC 前会先进行碎片整理默认值为0表示每次进入 Full GC 时都进行碎片整理。
3、详细说一下G1的回收过程
G1Garbage First回收器采用面向局部收集的设计思路和基于Region的内存布局形式是一款主要面向服务端应用的垃圾回收器。G1设计初衷就是替换 CMS成为一种全功能收集器。G1 在JDK9 之后成为服务端模式下的默认垃圾回收器取代了 Parallel Scavenge 加 Parallel Old 的默认组合而 CMS被声明为不推荐使用的垃圾回收器。G1从整体来看是基于 标记-整理 算法实现的回收器但从局部两个Region之间上看又是基于 标记-复制 算法实现的。
G1 回收过程G1 回收器的运作过程大致可分为四个步骤 初始标记会STW仅仅只是标记一下 GC Roots 能直接关联到的对象并且修改TAMS指针的值让下一阶段用户线程并发运行时能正确地在可用的Region中分配新对象。这个阶段需要停顿线程但耗时很短而且是借用进行Minor GC的时候同步完成的所以G1收集器在这个阶段实际并没有额外的停顿。 并发标记从 GC Roots 开始对堆中对象进行可达性分析递归扫描整个堆里的对象图找出要回收的对象这阶段耗时较长但可与用户程序并发执行。当对象图扫描完成以后还要重新处理在并发时有引用变动的对象。 最终标记会STW对用户线程做短暂的暂停处理并发阶段结束后仍有引用变动的对象。 清理阶段会STW更新Region的统计数据对各个Region的回收价值和成本进行排序根据用户所期望的停顿时间来制定回收计划可以自由选择任意多个Region构成回收集然后把决定回收的那一部分Region的存活对象复制到空的Region中再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动必须暂停用户线程由多条回收器线程并行完成的。
4、JVM中一次完整的GC是什么样子的
先描述一下Java堆内存划分。
在 Java 中堆被划分成两个不同的区域新生代 ( Young )、老年代 ( Old )新生代默认占总空间的1/3老年代默认占 2/3。
新生代有 3 个分区Eden、To Survivor、From Survivor它们的默认占比是 8:1:1。
新生代的垃圾回收又称Minor GC后只有少量对象存活所以选用复制算法只需要少量的复制成本就可以完成回收。
老年代的垃圾回收又称Major GC通常使用“标记-清理”或“标记-整理”算法。
再描述它们之间转化流程 对象优先在Eden分配。当 eden 区没有足够空间进行分配时虚拟机将发起一次 Minor GC。 在 Eden 区执行了第一次 GC 之后存活的对象会被移动到其中一个 Survivor 分区 Eden 区再次 GC这时会采用复制算法将 Eden 和 from 区一起清理存活的对象会被复制到 to 区 移动一次对象年龄加 1对象年龄大于一定阀值会直接移动到老年代。GC年龄的阀值可以通过参数 -XX:MaxTenuringThreshold 设置默认为 15 动态对象年龄判定Survivor 区相同年龄所有对象大小的总和 (Survivor 区内存大小 * 这个目标使用率)时大于或等于该年龄的对象直接进入老年代。其中这个使用率通过 -XX:TargetSurvivorRatio 指定默认为 50% Survivor 区内存不足会发生担保分配超过指定大小的对象可以直接进入老年代。 大对象直接进入老年代大对象就是需要大量连续内存空间的对象比如字符串、数组为了避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。 老年代满了而无法容纳更多的对象Minor GC 之后通常就会进行Full GCFull GC 清理整个内存堆 – 包括年轻代和老年代。
5、Minor GC 和 Full GC 有什么不同呢
Minor GC只收集新生代的GC。
Full GC: 收集整个堆包括 新生代老年代永久代(在 JDK 1.8及以后永久代被移除换为metaspace 元空间)等所有部分的模式。
Minor GC触发条件当Eden区满时触发Minor GC。
Full GC触发条件 通过Minor GC后进入老年代的平均大小大于老年代的可用内存。如果发现统计数据说之前MinorGC的平均晋升大小比目前old gen剩余的空间大则不会触发Minor GC而是转为触发full GC。 老年代空间不够分配新的内存或永久代空间不足但只是JDK1.7有的这也是用元空间来取代永久代的原因可以减少Full GC的频率减少GC负担提升其效率。 由Eden区、From Space区向To Space区复制时对象大小大于To Space可用内存则把该对象转存到老年代且老年代的可用内存小于该对象大小。 调用System.gc时系统建议执行Full GC但是不必然执行。
6、介绍下空间分配担保原则
如果YougGC时新生代有大量对象存活下来而 survivor 区放不下了这时必须转移到老年代中但这时发现老年代也放不下这些对象了那怎么处理呢其实JVM有一个老年代空间分配担保机制来保证对象能够进入老年代。
在执行每次 YoungGC 之前JVM会先检查老年代最大可用连续空间是否大于新生代所有对象的总大小。
因为在极端情况下可能新生代 YoungGC 后所有对象都存活下来了而 survivor 区又放不下那可能所有对象都要进入老年代了。这个时候如果老年代的可用连续空间是大于新生代所有对象的总大小的那就可以放心进行 YoungGC。但如果老年代的内存大小是小于新生代对象总大小的那就有可能老年代空间不够放入新生代所有存活对象这个时候JVM就会先检查 -XX:HandlePromotionFailure 参数是否允许担保失败如果允许就会判断老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小如果大于将尝试进行一次YoungGC尽快这次YoungGC是有风险的。如果小于或者 -XX:HandlePromotionFailure 参数不允许担保失败这时就会进行一次 Full GC。
在允许担保失败并尝试进行YoungGC后可能会出现三种情况 ① YoungGC后存活对象小于survivor大小此时存活对象进入survivor区中 ② YoungGC后存活对象大于survivor大小但是小于老年大可用空间大小此时直接进入老年代。 ③ YoungGC后存活对象大于survivor大小也大于老年大可用空间大小老年代也放不下这些对象了此时就会发生“Handle Promotion Failure”就触发了 Full GC。如果 Full GC后老年代还是没有足够的空间此时就会发生OOM内存溢出了。
通过下图来了解空间分配担保原则
7、什么是类加载类加载的过程
虚拟机把描述类的数据加载到内存里面并对数据进行校验、解析和初始化最终变成可以被虚拟机直接使用的class对象
类的整个生命周期包括加载Loading、验证Verification、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中准备、验证、解析3个部分统称为连接Linking。如图所示 加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的类的加载过程必须按照这种顺序按部就班地开始而解析阶段则不一定它在某些情况下可以在初始化阶段之后再开始这是为了支持Java语言的运行时绑定也称为动态绑定或晚期绑定
类加载过程如下 加载加载分为三步 1、通过类的全限定性类名获取该类的二进制流 2、将该二进制流的静态存储结构转为方法区的运行时数据结构 3、在堆中为该类生成一个class对象 验证验证该class文件中的字节流信息复合虚拟机的要求不会威胁到jvm的安全 准备为class对象的静态变量分配内存初始化其初始值 解析该阶段主要完成符号引用转化成直接引用 初始化到了初始化阶段才开始执行类中定义的java代码初始化阶段是调用类构造器的过程
8、什么是类加载器常见的类加载器有哪些
类加载器是指通过一个类的全限定性类名获取该类的二进制字节流叫做类加载器类加载器分为以下四种 启动类加载器BootStrapClassLoader用来加载java核心类库无法被java程序直接引用 扩展类加载器Extension ClassLoader用来加载java的扩展库java的虚拟机实现会提供一个扩展库目录该类加载器在扩展库目录里面查找并加载java类 系统类加载器AppClassLoader它根据java的类路径来加载类一般来说java应用的类都是通过它来加载的 自定义类加载器由java语言实现继承自ClassLoader 9、什么是双亲委派模型为什么需要双亲委派模型
当一个类加载器收到一个类加载的请求他首先不会尝试自己去加载而是将这个请求委派给父类加载器去加载只有父类加载器在自己的搜索范围类查找不到给类时子加载器才会尝试自己去加载该类
为了防止内存中出现多个相同的字节码因为如果没有双亲委派的话用户就可以自己定义一个java.lang.String类那么就无法保证类的唯一性。
补充那怎么打破双亲委派模型
自定义类加载器继承ClassLoader类重写loadClass方法和findClass方法。
10、说一下 JVM 调优的命令 jpsJVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。 jstatjstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。 jmapjmap(JVM Memory Map)命令用于生成heap dump文件如果不使用这个命令还阔以使用-XX:HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候·自动生成dump文件。 jmap不仅能生成dump文件还阔以查询finalize执行队列、Java堆和永久代的详细信息如当前使用率、当前使用的是哪种收集器等。 jhatjhat(JVM Heap Analysis Tool)命令是与jmap搭配使用用来分析jmap生成的dumpjhat内置了一个微型的HTTP/HTML服务器生成dump的分析结果后可以在浏览器中查看。在此要注意一般不会直接在服务器上进行分析因为jhat是一个耗时并且耗费硬件资源的过程一般把服务器生成的dump文件复制到本地或其他机器上进行分析。 jstackjstack用于生成java虚拟机当前时刻的线程快照。jstack来查看各个线程的调用堆栈就可以知道没有响应的线程到底在后台做什么事情或者等待什么资源。 如果java程序崩溃生成core文件jstack工具可以用来获得core文件的java stack和native stack的信息从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。