JVM总结

1. JVM的内存区域

JVM将内存分为五块区域分别是程序计数器、虚拟机栈、本地方法栈、堆和方法区

1.1 程序计数器

定义:

唯一一个不会发生内存溢出异常的内存区域.
保存的是当前JVM解释器执行命令的行号
最小的一块区域

1.2. 虚拟机栈

定义: 保存的是局部变量表等信息

局部变量表

  • 局部变量表

    • reference
    • 基本类型变量
    • returnAddress

1.3. 本地方法栈

和虚拟机栈差不多,保存的是本地方法的信息,在hotspot虚拟机中将虚拟机栈和本地方法栈合二为一

1.4. 堆

定义:
最大的一块内存区域.
存放的是对象的实例数据
JVM启动时创建
分为新生代、老年代

  • 新生代

  • 老年代

  • 元空间

    和永久代差不多,将class文件的元数据保存到元空间,元空间使用的是本地内存

1.5. 方法区

  • 运行时常量池

    定义: 存放的是class文件的常量池的数据

  • 常量

  • 静态变量

  • JIT及时编译后的代码

  • 类信息

2. 垃圾收集算法&垃圾收集器

介绍常用的垃圾收集算法和垃圾收集器

2.1 判断对象存活的算法

  • 引用计数

    定义: 只作为了解,没有虚拟机使用这种方式.

    有对象引用就+1,对象不引用就-1,计数器为0就回收对象.

    缺点: 无法解决对象循环引用问题

  • 可达性分析

    定义: 只要GCRoots连接对象的实例,对象就不能被回收

    • 虚拟机栈引用的对象
    • 方法区静态属性引用的对象
    • 方法区常量引用的对象
    • 本地方法区引用的 对象

2.2 垃圾收集算法

  • 标记清除

    定义: 用在老年代,收集的空间是不连续的,大对象无法分配时,可能会提前触发一次full GC.

  • 复制

    定义: 用在新生代,有一个Eden区和两个survivor区, 按8:1的比例,每次minor gc的时候会把Eden和一个survivor区的存活对象分配到另一个survivor区中,如果survivor区的空间不够,就直接分配到老年代

  • 标记整理

    定义: 和标记清除相比,就是整理的空间是连续的

  • 分代收集

    定义: 新生代用复制算法,老年代用标记清除或标记整理算法

2.3 垃圾收集器

  • 新生代

    • serial

      1. 单线程
      2. 进行垃圾收集,必须暂停其他所有工作线程,"Stop The World"
      3. 简单高效,Client模式下首选
    • parNew

      1.除了使用多条线程进行垃圾收集之外,其他与Serial相同
      2. 可以与CMS配合

    • parallel scavenger

      1. 吞吐量收集器
      2. 最大停顿时间参数(调低停顿时间,会增加停顿频率)
      3. 停顿比率参数(0-100)
      4. GC自适应的调节策略
  • 老年代

    • serial old

      1. 在CMS并发收集发生Concurrent Mode Failure时,作为备胎使用
    • cms

      • 停顿段,并发收集

      • 对CPU资源敏感

        CPU不足4个时,影响程序的性能

      • 无法清除浮动垃圾

        浮动垃圾: 和用户线程并行执行产生的新垃圾.

        这一部分垃圾无法回收,因为cms和用户线程行执行,所以需要留一部分内存给cms使用,老年代空间使用92%以上时启动cms,如果空间不够会报"Concurrent mode Failure",这时候会启动备用方案serial old进行垃圾回收.

      • 标记清除算法

        收集的空间是不完整的

    • parallel scavenger old
      parallel scavenger的老年代版本

  • G1

    特点:

    充分利用计算机资源
    分代收集
    空间整合
    建立可预测的停顿

    通过remember set解决全局扫描region对象互相引用问题. 在reference对象进行写操作的时候 ,发生一个写中断,如果有跨region引用就通过cardTable把信息记录到region的remember set中,在垃圾回收的时候通过枚举根节点和remember set就可以不会遗漏要回收的垃圾对象了.

    回收的四个步骤:

    初始标记
    并发标记
    最终标记
    筛选回收

    找到所有GCRoots,修改ntmd的值,在进行并发标记的时候,保证用户线程可以将对象分配在正确可用的region中
    用户线程和垃圾收集线程同时执行
    同时执行产生变动的那部分,记录到remember set logs 中,并把这个logs的内容放到 remember set中
    在用户规定的时间里,回收最大价值的region的垃圾

    • 特点

      • 充分利用计算机资源
      • 分代收集
      • 空间整合
      • 建立可预测的停顿
    • 垃圾收集步骤

      • 初始标记

        找到所有GCRoots,修改ntmd的值,在进行并发标记的时候,保证用户线程可以将对象分配在正确可用的region中

      • 并发标记

        用户线程和垃圾收集线程同时执行

      • 最终标记

        同时执行产生变动的那部分,记录到remember set logs 中,并把这个logs的内容放到 remember set中

      • 筛选回收

        在用户规定的时间里,回收最大价值的region的垃圾

2.3.1 垃圾收集器配合使用图

2.4 内存分配与回收策略

  • 对象优先在eden分配
  • 大对象直接进入老年代
  • 长期存活的对象将进入老年代
  • 动态对象年龄判定

同年龄的对象的大小超过整个Survivor区的一半,大于等于这个年龄的对象都会被放入老年代.

  • 空间分配担保流程图

之所以进行这么多选择,是为了尽全力避免Full GC.

3.1 实战

解决问题

  • 堆溢出

    报错: java.lang.OutOfMemoryError: Java heap space

    原因: 一般都是应该回收的对象没有回收造成的内存溢出.

    解决: 看是否有应该回收的对象没有回收,如果没有尝试扩大堆内存

  • 栈溢出

    报错: StackOverflowError

    原因: 递归调用太多,一般不会出现这种错误

    解决: 1. 调大栈深度 2. 从代码入手,改正错误的调用方法

  • 方法区逸出

    Java开始使用元空间替换永久代.

    元空间不在虚拟机中,使用的是本地内存.

    解决元空间导致的内存溢出的方法:

    先看是不是代码有错误,导致元空间占用过多的内存
    如果不是,那就只能扩展本机内存了

  • 本机直接内存溢出

    报错: java.lang.OutOfMemoryError: null
    at sun.misc.Unsafe.allocateMemory(Native Method) ~[na:1.8.0_201]

    解决:

    使用参数-XX:MaxDirectMemorySize=10M

    调大直接内存大小

  • gc日志分析

    设置参数: -Xloggc:D:/logs/admin_client.log

    需要提前建好目录

    • admin_client.log

设置虚拟机参数

  • -Xmx3550m 最大堆大小

  • -Xms3550m 最小堆大小

  • -Xmn2g 新生代

  • -Xss128k 虚拟机栈大小

    设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

  • 设置垃圾回收器

    在Java8中的测试,默认垃圾收集器Parallel GC是最快的,可以不进行更换

  • -XX:+HeapDumpOnOutOfMemoryError自动生成堆转储文件的参数

    -XX:+HeapDumpOnOutOfMemoryError

    报错: Failed to write core dump. Minidumps are not enabled by default on client versions

    加入参数: -XX:+CreateMinidumpOnCrash

    -Xms200m -Xmx200m -XX:+HeapDumpOnOutOfMemoryError -XX:+CreateMinidumpOnCrash
    

    生成的hprof文件可以使用Jprofiler直接打开

posted @ 2019-06-06 16:23  lbr617  阅读(401)  评论(0编辑  收藏  举报