JVM内存模型与垃圾回收

    技术2022-07-11  79

    JVM内存模型与垃圾回收

    JVM结构堆的内存模型垃圾回收算法垃圾回收(GC)什么对象需要回收什么时候进行GC如何进行GC垃圾收集器垃圾收集器相关参数串行收集器并行收集器CMSG1其它 JVM设置参数GC调试参数解释

    JVM结构

    1. JVM可划分为:堆、方法区、程序计数器、本地方法栈、虚拟机栈(栈) 线程共享区域:堆、方法区 线程私有区域:程序计数器、本地方法栈、栈 2. 各个区域的作用和存放类型 1)程序计数器 当前线程执行的字节码的行号指示器,记录指令执行的位置 2)虚拟机栈:基本数据类型值、对象引用、方法调用 为方法执行服务,每次调用方法都会创建方法栈,如果递归没有终止条件,则会造成StackOverFlow(SOF) 每个方法执行会创建一个栈,存储局部变量、操作栈、动态链接等 3)本地方法栈 本地方法栈是为Native方法服务 4)堆:主要存储对象和数组 5)方法区 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 6)运行时常量池(方法区一部分) 属于方法区一部分,用于存放编译期生成的各种字面量和符号引用 编译器和运行期(String 的 intern())都可以将常量放入池中 7)永久代 是hotspot独有的方法区的一种实现,在1.8被metaspace(元空间)取代,元空间使用的是本地内存 元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小: -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。 -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。 除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性: -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集 -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

    堆的内存模型

    1. 堆主要分为:新生代(young)和老年代(old) 2. 新生代:存放新创建的对象,一般占据1/3的堆内存 新生代又分为:Eden区、survivor from、survivor to Eden区:用于存放新创建的对象的区域 survivor from:也叫survivor0区,存放上一次GC后留下的对象 survivor to:也叫survivor1区,用于存放MinorGC时存活的对象 Eden : survivor from : survivor to = 8 : 1 : 1 3. 老年代:存放生命周期较长的对象,多次GC未被回收的对象

    垃圾回收算法

    1. 标记清除:Mark and Sweap 1)标记:标记所有和GCRoots可达的对象 2)清除:遍历堆,将没有标记的对象进行清除 缺点:需要对整块内存进行遍历,效率低,并且内存碎片化比较严重,影响存放效率(增加寻址时间) 2. 复制算法:Copy And Sweap 1)Copy:使用2块内存空间,当其中一块内存存满后,将这块内存的存活对象(可达对象)复制到另一块内存 2)Sweap:然后将内存全部清除,这样就达到了回收的目的 缺点:空间占用高、利用率低 3. 标记整理 1)标记:对所有GCRoots可达对象进行标记 2)整理:然后将标记对象移向内存一端,清除另一端的对象(也就是需要回收的对象) 优点:因为所有存活对象移向一端,不会出现大量不连续的内存空间(内存碎片化度低) 主要适合老年代的对象存储 4. 分代收集 根据新生代(Young Generation)和老年代(Old Generation)的特点采取最适当的收集算法 1)新生代:复制算法 新生代GC比较频繁,存活对象较少,因此复制算法效率较高 2)老年代:标记整理 / 标记清除 老年代对象存活率高,回收对象少,因此,可以采用标记整理或者标记清除

    垃圾回收(GC)

    什么对象需要回收

    对于JVM来说,不会被使用的对象就应该被回收,以便腾出内存空间,JVM有2种方式判断对象是否需要回收 1. 引用计数法 对对象的引用进行计数,引用计数为0的一定是可以回收的对象 但是也存在引用计数不为0,但是可以回收的对象,例如2个无用对象相互引用,这就有了可达性分析 2. 可达性分析 对于每一个活动对象,都存在以GC Roots为起点的引用路径,也叫对象可达路径 当一个对象与GC Roots间没有可达路径时,则代表该对象可被回收

    什么时候进行GC

    1. 新生代:MinorGC 当新生代的Eden区满了,无法存入新生对象,进行新生代的GC,这样的GC称为MinorGC 2. 老年代:MajorGC 新生代GC,有的对象可能晋升到老年代,造成老年代使用内存上升,如果此时老年代内存不足,则触发GC * 对于CMS,可以单独对老年代进行GC,其它的收集器会进行Full GC,所以通常Major GC 等同于Full GC 3. Full GC Full Gc 会回收新生代、老年代还有永久代(需要看版本,1.8没有永久代)的不可达对象,也就是说: Full GC 会触发 Minor GC 和 Major GC 触发Full GC的时机: 1)新生代平均晋升对象大小占用空间大于老年代剩余空间,触发Full GC,而不是只触发Young GC 2)如果存在永久代(Permanent Generation),当永久代没有足够内存,触发Young GC 3)显示调用System.gc()通知GC有可能会触发GC,此时的GC也是Full GC

    如何进行GC

    1. 新生代 新生代发生的是MinorGC,采用的是复制算法,当进行MinorGC时,过程如下: 1)将Eden和survivor0区(survivor from)的存活对象复制到survivor1区(survivor to) 注意:如果无法复制到survivor1区,则对象晋升到老年代 2)清除Eden与survivor0区(survivor from)的内存 3)将survivor1区的存活对象与survivor0区的幸存对象进行交换 2. 老年代 老年代发生的是MajorGC,采用的是标记清除 / 标记整理

    垃圾收集器

    1. JVM有3种类型的垃圾收集器:串行收集器,并行收集器,并发收集器 串行(Serial):只有一个线程去执行GC,并且会暂停其它工作线程直到GC完成 并行(Parallel):多个线程去执行GC,也会暂停所有工作线程直到GC完成 并发(concurrent):GC线程和工作线程同时执行 2. 串行收集器 SerialGC -- 新生代串行垃圾收集器 使用单线程、复制算法 Serial Old -- 老年代串行垃圾收集器 使用单线程、标记整理 3. 并行收集器 ParNew -- 新生代并行垃圾收集器 使用多线程、复制算法 Parallel Scavenge 收集器 -- 新生代并行垃圾收集器 使用多线程、复制算法 ParallelOld -- 老年代并行垃圾收集器 使用多线程、标记整理 4. Parallel Scavenge Parallel Scavenge相比于ParNew的最大区别就是:吞吐量优先,能够设置垃圾收集停顿时间 Parallel Scavenge是以吞吐量优先的收集器,旨在实现可控的吞吐量 可以将这里的吞吐量理解成:运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间) Parallel Scavenge控制吞吐量的参数: -XX:MaxGCPauseMillis 控制最大垃圾收集停顿时间,大于0的ms值,这是牺牲 -XX:GCTimeRatio 直接设置吞吐量的比值,(0,100)的整数 MaxGCPauseMillis是牺牲吞吐量和新生代空间来换取的,并不是设置越低越好 假设GCTimeRatio值为n,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集 Parallel Scavenge提供GC自适应的调节策略(GC Ergonomics):-XX:+UseAdaptiveSizePolicy 当采用该策略,新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio) 晋升老年代对象年龄(-XX:PretenureSizeThreshold)等参数不需要手动设置 JVM根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量 5. 并发收集器CMS:ConcMarkSweepGC(老年代并发垃圾收集器) CMS是以最短垃圾回收停顿时间为目标的垃圾收集器,采用并发标记清除 对响应时间的需求大于吞吐量的需求可以使用CMS并发收集 CMS回收过程: 1)初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象 2)并发标记(CMS concurrent mark):可以和用户线程并行执行,标记所有可达对象 3)重新标记(CMS remark):标记并发标记过程中用户线程产生的垃圾对象 4)并发清除(CMS concurrent sweep):和用户线程可以并行执行,清除标记过的对象 优点:并发、低停顿 缺点:产生大量内存碎片,空间利用率不高 6. G1垃圾收集器:可对新生代和老年代进行回收(java9默认垃圾回收器) G1:大体流程来看是基于标记整理 G1:基于并发,采用复制算法 将堆在逻辑上划分为多个Region 1) 初始标记:标记GC Roots的直接引用对象 2) 并发标记:进行可达性分析,标记所有GCRoots的对象引用 3) 最终标记:对并发标记期间的对象进行重新标记 4) 筛选回收:对Region进行垃圾回收

    垃圾收集器相关参数

    串行收集器

    参数描述-XX:+UseSerialGC在新生代和老年代使用串行回收器-XX:+SuivivorRatio设置 eden 区大小和 survivor 区大小的比例-XX:+PretenureSizeThreshold设置大对象直接进入老年代的阈值,当对象的大小超过这个值时,将直接在老年代分配-XX:MaxTenuringThreshold设置对象进入老年代的年龄的最大值,每一次 Minor GC 后,对象年龄就加 1,任何大于这个年龄的对象,一定会进入老年代

    并行收集器

    参数描述-XX:+UseParNewGC在新生代使用并行收集器-XX:+UseParallelOldGC老年代使用并行回收收集器-XX:ParallelGCThreads设置用于垃圾回收的线程数,通常情况下可以和 CPU 数量相等。但在 CPU 数量比较多的情况下,设置相对较小的数值也是合理的-XX:MaxGCPauseMills设置最大垃圾收集停顿时间。它的值是一个大于 0 的整数。收集器在工作时,会调整 Java 堆大小或者其他一些参数,尽可能地把停顿时间控制在 MaxGCPauseMills 以内-XX:GCTimeRatio设置吞吐量大小,它的值是一个 0-100 之间的整数。假设 GCTimeRatio 的值为 n,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集-XX:+UseAdaptiveSizePolicy打开自适应 GC 策略。在这种模式下,新生代的大小,eden 和 survivor 的比例、晋升老年代的对象年龄等参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点

    CMS

    参数描述-XX:+UseConcMarkSweepGC新生代使用并行收集器,老年代使用 CMS+串行收集器-XX:+ParallelCMSThreads设定 CMS 的线程数量-XX:+CMSInitiatingOccupancyFraction设置 CMS 收集器在老年代空间被使用多少后触发,默认为 68%-XX:+UseFullGCsBeforeCompaction设定进行多少次 CMS 垃圾回收后,进行一次内存压缩-XX:+CMSClassUnloadingEnabled允许对类元数据进行回收-XX:+CMSParallelRemarkEndable启用并行重标记-XX:CMSInitatingPermOccupancyFraction当永久区占用率达到这一百分比后,启动 CMS 回收,前提是-XX:+CMSClassUnloadingEnabled 激活了-XX:UseCMSInitatingOccupancyOnly表示只在到达阈值的时候,才进行 CMS 回收-XX:+CMSIncrementalMode使用增量模式,比较适合单 CPU

    G1

    参数描述-XX:+UseG1GC使用 G1 回收器-XX:+UnlockExperimentalVMOptions允许使用实验性参数-XX:+MaxGCPauseMills设置最大垃圾收集停顿时间-XX:+GCPauseIntervalMills设置停顿间隔时间

    其它

    参数描述-XX:+DisableExplicitGC禁用显示 GC

    JVM设置参数

    参数描述-Xms初始堆大小,-Xms1024m-Xmx最大堆大小,-Xmx2048m-Xmn新生代大小,通常为Xms的1/3或1/4,包括Eden和2个survivor区-Xss每个线程堆栈的大小,默认为1M,JDK1.5+支持-XX:NewRatio新生代:老年代,-XXNewRatio=2,代表新生代占1/3,老年代占2/3-XX:SurvivorRatioEden:survivor,默认为8,即Eden占8/10,survivor0和1各占1/10-XX:PermSize永久代的大小-XX:MaxPermSize永久代的最大值-XX:+PrintGCDetails打印GC信息-XX:+HeapDumpOnOutOfMemoryError让JVM发生内存溢出时Dump出内存堆转储快照,方便分析原因

    GC调试参数解释

    S0C:新生代survivor0的大小 S1C:新生代survivor1大小 S0U:新生代survivor0的使用大小 S1U:新生代survivor1的使用大小 EC:Eden的大小 EU:Eden的使用大小 OC:老年代大小 OU:老年代使用大小 MC:方法区大小 MU:方法区使用大小 CCSC:压缩类空间大小 CCSU:压缩类空间使用大小 YGC:年轻代垃圾回收次数 YGCT:年轻代垃圾回收消耗时间 FGC:老年代垃圾回收次数 FGCT:老年代垃圾回收消耗时间 GCT:垃圾回收消耗总时间
    Processed: 0.017, SQL: 9