zoukankan      html  css  js  c++  java
  • 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相同

        1. 可以与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直接打开

  • 相关阅读:
    ISO9126 软件质量模型
    java 15.String
    java 14. ArrayList常用方法
    java 13. 方法重载构造方法块this用法
    linux ssh连接心跳检查断开连接
    关于递归,我有几句话想说
    pytest 报错 ImportError: cannot import name 'main'
    递归回溯剪枝之斐波那契数列
    appium-doctor诊断信息不完整
    数据驱动,关键字驱动,混合驱动简单模型
  • 原文地址:https://www.cnblogs.com/xisuo/p/10985690.html
Copyright © 2011-2022 走看看