JVM内存结构和垃圾回收简介

JVM相关知识是性能测试必须要了解的,同时也是面试中经常遇到的问题。

 

JVM内存管理机制

JVM简介

  • Java采用了自动管理内存的方式
  • Java程序是运行在JVM之中的
  • Java的跨平台是基于JVM的跨平台特性
  • 内存的分配和对象的创建是在JVM中
  • 用户可以通过一系列参数来配置JVM

 

JVM运行时区域

 

 

JVM内存结构

一、栈内存

  • 线程私有
  • 生命周期和线程相同
  • 主要存放内容:
    • 基本数据类型(int,char,float,double...)
    • 对象的引用,指向了对象在堆内存中起始地址
    • 通过-Xss参数 配置,设置每个线程的堆栈大小

 

 二、堆内存

  • 堆内存是JVM中空间最大的区域
  • 所有线程共享堆
  • 所有的数组以及内存对象的实例都在此区域分配
  • 堆内存大小通过参数进行配置:
    • -Xmx:最大堆内存
    • -Xms:最小堆内存,此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
    • -Xmn:设置年轻代大小
  • 堆内存的构成,如上图所示:
    • 新生代:包括三块区域,eden、from survivor(s0)、to survivor(s1)
    • 老年代:old gen
  • 堆内存数据变化:

    1、初始化对象首先放在新生代eden区

    2、eden区满了之后,对eden区进行扫描,将仍然存活的对象移到s0区,同时对eden区和是s1区进行清扫工作

    3、新创建的对象继续存在eden区,eden满了之后,再次扫描eden和s0区,将存活的对象放在s1区,将eden和s0清空

    4、新创建的对象继续存在eden区,eden满了之后,再次扫描eden和s1区,将存活的对象放在s0区,将eden和s1清空,如此循环往复。(如果对象在新生代中存活15次,存入老年代)

    5、如果从eden区和s0区存入s1时,s1放不下,则将对象放在老年代中,将整个新生代全部清空。

    (备注:线程结束,对象的实例失去引用,在栈内存中没有地址,则认为对象无用)

  • 栈内存和堆内存举例:

    Object o = new Object()

    其中,o存放在栈内存中,new Object()存在在堆内存中,变量o是Object对象的引用,o上存放了Object对象占用内存的起始地址

 

三、永久代

  • 永久代也叫(Method Area)
  • 各线程共享,主方法区要存放类信息、常量、静态变量,如public static int a = 2
  • 垃圾回收行为比较少见

 

四、JVM结构总结

Survivior = s0+s1

年轻代 = Eden + Survivor

年轻代 = Eden + s0 + s1

堆内存 = 年轻代 + 老年代

堆内存 = Eden + s0 + s1 + 老年代

 

五、Java8新变化

Java8从JVM中移除了PermGen,使用Metaspace(元空间)来代替永久代

  • Metaspace不存在JVM中,而是存在本地内存中
  • 配置元空间初始值和最大值参数:
    • -XX:MetaspaceSize=64m
    • -XX: MaxMetaspaceSize=64m

 

JVM垃圾回收

一、YoungCG和FullGC

新生代引发的GC叫YoungCG,上面内存结构的时候我们提到eden区向s0区存放对象后,清空eden区和s1区就是YoungGC

老年代引发的GC叫FullGC。FullGC会引起整个JVM的用户线程暂停,待垃圾回收完毕后,才继续运行。老年代引发的GC会引起整个堆内存的全局GC。GC的时间长短跟堆内存空间大小有关系。

 

二、永久代(元空间)的垃圾回收

主要回收:

  • 废弃的常量
  • 无用的类:
    • 类的所有实例都已经被回收
    • 加载该类的ClassLoader已经被回收
    • 该类的Class对象没有在任何地方被引用

 

三、堆垃圾回收算法

1、标记-清除算法

(1)分为标记和清除两个阶段,标记完成后,统一回收

(2)标记和清除过程的效率都不高,而且标记清除后会产生大量不连续的内存碎片,如下图

 

2、复制算法

(1)内存分为相等的两块,当一块的内存用完,将存活对象复制到另外一块,将原内存一次性全部清理掉。复制的时候按顺序分配内存,无内存碎片问题,如下图。

(2)将内存分为两半,空间永远只能使用1/2,利用率低

(3)新生代垃圾回收使用此算法

 

3、标记-压缩算法

(1)先对存活对象进行标记,让存活对象向一边移动,然后清理掉存活对象边界外的所有内存

(2)老年代垃圾回收使用的就是此算法

 

4、分代收集算法

新生代YoungGC采用复制算法 

老年代FullGC采用标记-压缩算法 

 

四、垃圾收集器

垃圾收集器是内存回收算法的具体实现,JVM不同的区域可以采用不同的垃圾收集器组合,主要有以下几种:

1、Serial收集器(串行)

(1)单线程收集器,串行

(2)JVM中用户线程全部停止

(3)Client模式下,新生代默认使用此收集器(机器配置较低情况下)

(4)简单、高效(机器配置比较低的情况下,单线程可能比多线程效率高)

 

2、ParNew收集器(并行)

(1)并行收集器,Serial收集器的多线程版本

(2)Server模式下JVM默认的新生代收集器

(3)默认开启的垃圾回收线程与CPU核数一致

 

 

3、CMS收集器(ConcurrentMarkSweep)(并发)

(1)采用了标记-清除、标记-压缩算法

(2)并发收集、低停顿

(3)会消耗cpu、会产生内存碎片、会有浮动垃圾(Concurrent Mode Failure)

(浮动垃圾:并发清理的时候用户线程还在运行,清理的同时还在产生新垃圾,必须在空间占用70%-90%的时候就进行垃圾回收,防止浮动垃圾产生的速度大于并发清理的速度)

(4)收集器不重:

    <1>初始标记:只会标记根对象,这个过程很快,此时用户线程会停掉;

    <2>并发标记:通过根对象搜索,跟用户线程一起操作;

    <3>重新标记:用户线程也会停掉,标记第<2>步新产生的垃圾,速度很快

 

五、内存溢出

1、内存溢出

堆内存溢出(OutOfMemory:Java heap space):堆内存中存在大量对象,这些对象都有被引用。当所有对象占用空间达到堆内存的最大值,就会出现内存溢出。

永久代溢出(OutOfMemoryError:PermGen space):类的一些信息,例如类名、访问修饰符、字段描述、方法描述等,所占空间大于永久代最大值,就会出现溢出。如果存在问题,程序启动阶段就会报错。

 

2、内存溢出检测方法

(1)图形界面:Jconsole、Jvisualvm

(2)命令行工具:

    Jstat –gcutil pid 1000 100

    Jmap –histo pid | head -20

    Jmap –heap pid

 

六、JVM常见参数

1、-Xms2048m,初始堆大小,建议<物理内存的1/4,默认值为物理内存的1/64

2、-Xmx2048m,最大堆大小,建议与-Xms保持一致,默认值为物理内存的1/4

3、-Xmn512m,新生代大小,建议不超过堆内存的1/2

4、-Xss256k,线程堆栈大小,建议256k

5、-XX:PermSize=256m,永久代初始值,默认值为物理内存的1/64

6、-XX:MaxPermSize=256m,永久代最大值,默认值为物理内存的1/4

7、-XX:SurvivorRatio=8,新生代中eden区和Survivor区的比例,默认为8:1,即Eden(8),From Space(1),To Space(1)

8、-XX:UseConcMarkSweepGC,开启CMS垃圾回收器

 

CMS相关参数

-XX:+UseConcMarkSweepGC:默认关闭,ParNew+CMS+Serial Old,当CMS收集器出现 ConcurrentModeFailure错误(Jvm预留空间不足以容纳程序使用),采用后备收集器Serial Old -XX:CMSInitiatingOccupancyFraction=80:CMS收集器在老年代空间被使用多少时触发FullGC,默认为92

-XX:+UseCMSCompactAtFullCollection:CMS收集器在FullGC时开启内存碎片的压缩,默认关闭

-XX:CMSFullGCsBeforeCompaction=8:执行多少次不压缩FullGC后,进行一次压缩,默认是0(代表每次 FullGC都进行压缩)

-XX:+UseCMSInitiatingOccupancyOnly:使用手动定义初始化定义开始,禁止hostspot自行触发CMS GC

-XX:ParallelGCThreads=8:并行收集器的线程数,此值最好配置与处理器数目相等 同样适用于CMS

 

日志参数:

-XX:+HeapDumpOnOutOfMemoryError:当发生内存溢出时,进行堆内存dump-XX:+PrintGCDetails:打印 GC的详细信息码同学 码同

posted @ 2022-04-05 11:13  阳光倾林  阅读(192)  评论(0编辑  收藏  举报