JVM -- 基础知识

小结下

image-20210915101107972

  1. JVM的组成部分,及其作用

    • 组成部分:
      • 类加载器(ClassLoader)
      • 运行时数据区(Runtime Data Area)
      • 执行引擎(Execution Engine)
      • 本地库接口(Native Interface)
    • 作用:
      1. 首先通过类加载器会把Java代码转成字节码
      2. 运行时数据区再把字节码加载到内存中,但是字节码只是JVM的一套指令规范,底层操作系统并不能去执行,需要翻译成特定的命令
      3. 命令解析器执行引擎,将字节码翻译成底层系统指令,再交给CPU去执行
      4. 这个过程中需要调用其它语言的本地库接口来实现整个程序的功能

  2. JVM的运行时数据区

    • 不同的虚拟机的运行数据区可能会略有区别,但都会遵循Java虚拟机的规范,所以大体上可以分为5部分
    1. 程序计数器(Program Counter Register):当前程序所执行的字节码的行号指示器,字节码解析器就是通过改变这个计数器的值,来选取吓一跳需要执行的字节码指令,分支,循环,跳转,异常处理,线程回复等基础功能都依赖于这个计数器来完成
    2. Java虚拟机栈(Java Virtual Machins Stack):用于存储局部变量表,操作数栈,动态链表,方法出口等信息
    3. 本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务Java方法的,而本地方法栈是虚拟机调用Native方法服务的
    4. Java堆(Java Heap):Java虚拟机中内存最大的一块,是所有的线程共享的,几乎所有的对象实例都在这里分配内存
    5. 方法区(Method Area):用于存储已被虚拟机加载的类信息、常量,静态变量,即时编译后的代码等

  3. 堆和栈的区别

    区别
    功能 用来存放对象 用来执行程序
    共享 线程共享 线程私有
    空间大小 远大于栈

  4. 内存中的栈(stack),堆(heap)和静态区(static area)的用法

    • 通常定义一个基本类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;而通过new关键字和构造器创建的对象存放在堆空间;程序中的字面量(Literal),如直接书写的100,"hello"和常量都是存放在静态区中。
    • 栈空间操作起来最快但是空间很小,通常大量的对象多少存放在堆空间,理论上整个内存没有被其它线程使用的空间甚至硬盘的虚拟内存都可以被当成栈空间来使用

  5. 类的生命周期

    • 类的生命周期包括:加载、连接、初始化、使用、卸载;(前三部是类的加载过程)
    1. 加载:查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类对象
    2. 连接:连接包含三部分(验证、准备,解析)
      1. 验证:文件格式,元数据,字节码,符号引用验证
      2. 准备:为类的静态变量分配内存空间,并初始化为默认值
      3. 解析:把类中的符号引用转换为直接引用
    3. 初始化:为类的静态变量赋予正确的初始值
    4. 使用:实例对象并对其进行使用
    5. 卸载:执行垃圾回收

  6. Java对象创建的过程

  7. 垃圾回收器怎么判断对象是否可以回收

    • 引用计数器:为每个对象创建一个引用计数,有对象引用时将计数器+1,引用被释放时将计数器-1,当计数器为0时就可以被回收,缺点是不能解决循环引用问题
    • 可达性分析:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链时,则证明次对象是可以被回收的
  8. 什么是类加载器

    • 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立在JVM中的唯一性,每一个类加载器,都有一个独立的类名称空间。类加载器就是根据指定限定类名称将class文件加载到JVM内存,然后再转换为class对象
    • 类加载器的分类:
      • 启动类加载器(Bootstrap ClassLoader):是虚拟机自身的一部分,用来加载Java_Home/lib/目录中的,或者被-Xbootclasspath参数所指定的路径中并且被虚拟机识别的类库
    • 其它类加载器:
      • 扩展类加载器(Extension ClassLoader):负责加载\lib\ext目录或Java.ext.dirs系统变量指定的路径中的类库
      • 应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。

  9. 什么是双亲委派模型

    • 双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载器请求都会被传递到最顶层的启动类加载器中,只有当父类无法完成加载请求(在它的搜索范围内没有找到需求的类)时,才会尝试交给子类去加载类

  10. 类装载的执行过程

    一般分为5步:

    1. 加载:根据查找路径找到相应的class文件然后导入
    2. 检查:检查加载的class文件的正确性
    3. 准备:给类中的静态变量分配内存空间
    4. 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标识,而在直接引用指向内存中的地址
    5. 初始化:堆静态变量和静态代码执行初始化工作

  11. Java都有哪些引用类型

    1. 强引用:发生gc时不会被回收
    2. 软引用:有用但不是必须的对象,发生在内存溢出之前会被回收
    3. 弱引用:有用但不是必须的对象,在下一次gc时会被回收
    4. 虚引用:无法通过引用获得对象,用PhantomReference实现虚引用,虚引用的用途是在gc时返回一个通知

  12. JVM都有哪些垃圾回收算法

    1. 标记-清除算法:标记无用的对象,然后进行清除回收,缺点:效率不高,会产生内存碎片
    2. 标记-整理算法:标记无用的对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存
    3. 复制算法:按照容量划分为两个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后将已使用的内存空间一次清空,缺点:内存使用率不高,只有原来的一半
    4. 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法

  13. JVM都有哪些垃圾回收器

    1. Serial收集器:串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。
    2. ParNew收集器:ParNew收集器其实就是Serial收集器的多线程版本。
      Parallel收集器,Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。
    3. Parallel Old 收集器:Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
    4. CMS收集器:CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
    5. G1收集器:G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征

  14. 简述分代垃圾回收器是怎么工作的

    1. 分代回收器有两个区(新生代,老年代),新生代默认空间占1/3,老年代是2/3;新生代采用复制算法,新生代里分为3个区:Eden、To Survivor、From Survivor,默认占比为 8 : 1 : 1
    2. 执行流程:把Eden + From Survivor存活的对象放入To Survivor区;清空Eden和From Survivor区;From Survivor和To Survivor分区进行交换;每次在From Survivor交换到To Survivor时都存活的对象年龄+1,当年龄达到15(默认)时,升级为老年代。大对象也会直接进入老年代。
    3. 当老年代空间占到某个值之后就会触发全局垃圾回收,一般采用标记整理算法。

  15. JVM调优工具

    • JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具,第三方有:MAT(Memory Analyzer Tool)、GChisto。
      1. jconsole:用于对 JVM 中的内存、线程和类等进行监控;
      2. jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。
      3. MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗
      4. GChisto,一款专业分析gc日志的工具
  16. 什么是OutOfMemory问题,常见的原因有哪些

    • 内存加载的数据连太大,一次性从数据库获取太多数据
    • 集合类中有对对象的引用,使用后未清空,GC不能进行回收
    • 代码中存在循环产生过多的重复对象
    • 启动参数内存值较小
  17. StackOverflow异常,出现的情况

    • 栈内存溢出,一般由栈内存的局部变量过爆了,导致内存溢出。出现在递归方法,参数个数过多,递归过深,递归没有出口。
  18. 调优命令

    • Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo

      1. jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
      2. jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
      3. jmap,JVM Memory Map命令用于生成heap dump文件
      4. jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
      5. jstack,用于生成java虚拟机当前时刻的线程快照。
        jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。
  19. 常用的JVM调优的参数有哪些

    • -Xms2g:初始化推大小为 2g;
    • -Xmx2g:堆最大内存为 2g;
    • -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
    • -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
    • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
    • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
    • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
    • -XX:+PrintGC:开启打印 gc 信息;
    • -XX:+PrintGCDetails:打印 gc 详细信息。

posted @ 2021-09-15 10:14  hehell  阅读(62)  评论(0)    收藏  举报