JVM 备忘

187 阅读8分钟

JVM

JVM是什么

JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器执行指令;

  • JVM有两个子系统和两个组件,

    1. 两个子系统为CLass Loader(类装载)、Execution engine(执行引擎);

    2. 两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口);

    • Class Loader:根据给定的权限定名类名(如:java.lang.Object)类装载class文件到Runtime data area中的method area;
    • Execution engine:执行class中的指令
    • Native Interface:与native libraries交互,是其他编程语言交互的接口
    • Runtime data area:JVM的内存区域
  • JVM执行过程

    new Girl() —编译成class文件—>系统类加载系统—将字节码文件加载JVM—>组件运行时数据区域(JVM内存)—将字节码解析成底层系统指令—>系统引擎—>组件本地接口—>Linux OR Windows

为什么要学习JVM

JVM提供了一个非常重要的功能就是内存管理。相对于C、C++语言每次去申请空间都要手动的区allcate,使用结束之后还要搜东free掉。JVM从这个层面释放程序员们对内存分配和管理的精力,只需要去关注业务逻辑实现,不在需要花费更多的心力在内存分配和回收上。

JVM帮我们管理了内存是帮我们省事了,但当代码写的不恰当的时候会导致内存溢出或者内存泄漏,这个时候如果你对JVM一无所知,就无法快速定位和处理问题

JVM运行时内存结构

jvm.jpg

  • PC寄存器(程序计数器):每个线程启动的时候,都会创建一个程序计数器,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令。
  • 栈(虚拟机栈):各种基本数据类型(booleanbytecharshortintfloatlongdouble)对象引用(引用指针并非对象本身)
  • 本地方法栈:Java调用非java代码的接口,该方法实现由非Java语言实现
  • 方法区:用于存储虚拟机加载的:静态变量+常量+类信息+运行时常量池(类信息:类的版本、字段、方法、接口、构造函数的描述信息)
  • 堆:所有的对象实例以及数组都要在堆上分配,此内存区域唯一目的就是存放对象实例,堆是Java虚拟机所管理的内存中最大的一块,所有线程共享的一块内存区域,在虚拟机启动时创建。

IMG_4699.JPG

  • 从变量的角度来分析

    • 局部变量:
      • 基本类型的值存在栈中。如age=18
      • 如果是对象的实例,则只存储对象实例的引用。如Boy=ref
    • 实例变量:存放在堆中的对象实例中。如Boy的实例变量name=ref
    • 静态变量:存放在方法区中的常量池中。如Boy.class中的Girl=ref
  • 从内存区域来分析

    • 虚拟机栈:只存放局部变量
    • 堆:存储对象的实例
    • 方法区:存放class信息和常量信息

    JVM调优

  • 调试工具

    JvisualVM是JDK自带的一款全能型性能监控和故障分析工具,包括对CPU使用,JVM堆内存消耗、线程、类加载的实时监控,内存dump文件分析,垃圾回收运行情况的可视化分析等,堆故障排查和性能调优很有帮助。

    监视——>堆(dump)——>查找——>一般都是SQL(sql dao)——>点开接口——>h——>sqlSession——>sqlSessionFactory——>configuration——>右击显示实例——>在类型里找PrepareStatementHandler——>右击显示实例——>boundSql——>sql——>显示实例

  • Sql优化

    • 分库分表
    • 建立索引
    • 搜索引擎

常见问题

  • 介绍下JVM内存模型

    JVM分为堆区和栈区,还有方法区。初始化的对象放在堆里面,引用放在栈里面,class类信息常量池(static常量和static变量)等放在方法去

    • 方法区:主要是存储类信息,常量池(static常量和static变量),编译后的代码(字节码)等数据
    • 堆:初始化的对象。成员变量(那种非static变量),所有的对象实例和数组都要在堆上分配
    • 栈:栈的结构是栈帧组成的,调用一个方法就压入一帧,帧上面存储局部变量表,操作数栈,方法出口等信息,局部变量表存放的是8大基本类型加上应用类型,所以还是一个指向地址的指针
    • 本地方法栈:主要为native方法服务
    • 程序计数器:记录当前线程执行的行号
  • 说一说类加载的过程

    类装载分为以下5个步骤

    • 加载:根据查找路径找到相应的class文件然后导入

    • 验证:检查加载的class文件的正确性

    • 准备:给类中的静态变量分配内存空间

    • 解析:虚拟机将常量池中的符号引用替换成直接引用的过程,符号引用就理解为一个标识,而在直接引用指向内存中的地址

    • 初始化:对静态变量和静态代码块执行初始化工作

  • 那些区域可能发生OutOfMemory异常

    • Java堆(区域)-存放对象的实例
      • 异常信息:java.lang.OutOfMemory Error:Java heap space
      • 参数:-Xms(初始化堆),-Xmx(最大堆),-Xmn(新生代)
    • 虚拟机栈和本地方法栈(区域)-控制方法的执行
      • 异常信息:java.lang.OutOfMemory Error
      • 参数:-Xss
    • 方法区(区域)-存放Class的相关信息,如类名,访问修饰符,常量池,字段描述,方法描述等
      • 异常信息:java.OutOfMemory Error:PerGen space
      • 参数:-XX:PermSize -XX:MaxPermSize
    • 本机直接内存(区域)-如NIO,就是直接通过此内存实现
      • 异常信息:java.lang.OutOfMemory Error,有allocate,Native等
      • 参数:-MaxDirectMemorySize如不执行则与-Xmx一致
  • 垃圾收集的方法有哪些

    • 标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片
    • 复制算法:按照容量划分两个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一般
    • 标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界意外的内存
    • 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法
  • 说一下JVM的主要组成部分及其作用

    JVM包含两个子系统和两个组件

    两个子系统为Class loader(类装载)、Execution engine(执行引擎)

    两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)

    • Class Loader(类装载):根据给定的全限定名类型(如:lang.lang.Object)来装载class文件到Runtime data area中的method area
    • Execution engine(执行引擎):执行classes中的指令
    • Native Interface(本地接口):与native libraries交互,是其他编程语言交互的接口
    • Runtime data area(运行时数据区域):这就是我们常说的JVM的内存

    作用:首先通过类加载器(ClassLoader)会把Java代码转换成字节码,运行时数据区(Runtime data area)再把字节码加载到内存中,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由CPU去执行,而这个过程中需要调用其他语言的本地接口(Native Interface)来实现整个程序功能

  • 说一下JVM调优工具

    JDK自带了很多监控工具,都位于JDK的bin目录下,其中最常用的是jconsole和jvisualvm这两款试图监控工具

    • jconsole:用于对JVM中的内存、线程和类等进行监控
    • jvisualvm:JDK自带的全能分析工具,可以分析:内存块照、线程快照、程序死锁、监控内存的变化、gc变化等
  • 生产环境CPU占用过高如何解决

    问题详细描述:生产环境上出现了OutOfMenoryError,伴随着这个问题随之而来的是Full GC,CPU百分之百,频繁宕机重启等问题,严重影响业务的推广和使用,想优化代码,但是代码量很大,不可能把所有代码都筛查一边,如何定位问题

    • 重启服务
    • 通过JDK自带的jvisualvm监控工具故障处理分析问题
    • 通过堆页面查找保留大小最大的对象
    • 重点关注前几个对象
    • 分析问题,通过工具查询到sql或代码
    • 对sql语句进行分析优化
    • 重新发布版本