JVM知识回顾

JVM知识回顾

1. 简述JDK,JRE和JVM之间的关系

jdk架构
  • JDK:

    • 是用于支持Java程序开发的最小环境,基本上Java程序设计语言、Java虚拟机、Java API类库这三部分

    • JDK=JRE+java开发工具包

    • 作用:java程序的开发环境

  • JRE:

    • 是支持Java程序运行的标准环境,Java API类库中的Java SE API自己和Java虚拟机这两部分

    • java运行环境=JVM+核心类库

    • 作用:java程序的运行环境

  • JVM:

    • 保证 Java程序设计语言的安全特性和java语言的跨平台性
    • 一次编译,到处运行(Write once,run anywhere)

    简言之,使用 jdk 开发的java程序,交由 JRE 来运行,由 JVM 来保证跨平台

2. 类加载机制的作用和过程

一句话解释:类的加载指的是将.class文件中的二进制数读入到内存中,将其放在运行数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
类的生命周期

类的加载过程包括加载、验证、准备、解析、初始化五个阶段

1)加载

​ 在加载阶段,虚拟机主要做了三件事

  1. 通过一个类的全限定类名来获取其定义的二进制字节流
  2. 将这个字节流代表的静态存储结构转化为方法区的运行时数据结构
  3. 在堆中生成一个代表这个类的Class对象,作为方法区中这些数据的访问入口

2)验证

​ 保证被加载类的准确性

  1. 文件格式的验证:验证.class文件字节流是否符合class文件的格式规范,并且能够被当前版本的虚拟机处理。这里主要对魔数、主版本号、常量池等等的校验
  2. 元数据验证:主要对字节码描述的信息进行语义分析,以保证其描述的信息符合java语言规范的要求。比如说验证这个类是不是有父类,类中的字段方法是不是和父类有冲突
  3. 字节码验证:这是整个验证过程中最复杂的阶段,主要是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在元数据验证阶段对数据类型做出验证后,这个阶段主要对类的方法做出分析,保证类的方法在运行时不会做出危害虚拟机的事。
  4. 符号引用验证:他是验证的最后一个阶段,发生在虚拟机将符号引用转化为直接引用的时候。主要是对类自身以外的信息进行校验。目的是确保解析动作能够完成。

3)准备

​ 准备阶段主要为类变量分配内存并设置初始值

  1. 类变量(static)会分配内存,但实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中

  2. 这里的初始值值得是数据类型默认值,不是代码中被显示赋予的值。比如

    public static int a = 1;
    

    这里的a在准备阶段过后值为0,而不是1。赋值为1的动作在初始化阶段。

4)解析

​ 解析阶段主要是虚拟机将常量池中的符号引用转为直接引用的过程

  • 符号引用:以一组符号来描述所引用的目标,可以是任何形式的字面量。classfile中的内容,没有实际含义
  • 直接引用:直接引用是可以指向目标的指针、相对偏移量或者是一个能直接或间接定位到目标的句柄。和虚拟机实现的内存有关,不同的虚拟机直接引用一般不同。在java进程中能够代表真实含义的

5)初始化

​ 主要为类的静态变量赋予正确的初始值,有两种方式

  1. 声明类变量时指定初始值
  2. 使用静态代码块为类变量指定初始值

3. 运行时数据区分为哪几块?说说你对每块区域的理解(某些存储的内容,生命周期,作用等)

运行时数据区

​ 运行时数据区分为方法区、堆、虚拟机栈、本地方法栈、程序计数器

  1. 程序计数器:线程私有,可以看成是当前线程所执行的字节码的行号指示器,用于选取下一条需要执行的指令,也是唯一一个没有OOM情况的区域,与线程共存亡
  2. Java虚拟机栈:线程私有,为JVM执行Java方法服务,主要描述Java方法执行的线程内存模型,与线程共存亡
  3. 本地方法栈:线程私有,与虚拟机栈相似,为JVM使用到的Native方法服务,Native方法多用C++写
  4. Java堆:线程共享,主要用于存储实例对象,Java中几乎所有的对象实例都会存储到这块内存中,考虑到即时编译和逃逸分析,有一部分的对象实例会分配到栈上
  5. 方法区:线程共享,主要用于存储被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据
  6. 运行时常量池:线程共享,属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用

4. 结合Eden,S0,S1和Old区,描述一下一个对象创建的过程

​ 对象的分配,从理论上来讲应该都是在堆上分配(即时编译和逃逸分析,会分配到栈上)。在正常分代的情况中,新生成的对象会分配在新生代中,但是少数情况下(比如对象大小超过一定阈值)会直接分配到老年代。

​ 大多数情况下,对象在Eden区中分配,当Eden区没有足够空间时,虚拟机会发起一次Minor GC,新生代采用的是复制算法,把存活的对象从Eden和S0复制到S1区,后把对象年龄加一,并清空Eden和S0(新生代的对象大多为活跃的对象,会频繁的创建和销毁,所以新生代GC时应该存活的对象很少,所以采用复制算法是最合适的)。当对象达到一定年龄之后(默认15岁,可修改-XX:MaxTenuringThresold=需要的年龄数字),对象会被移动到老年代,当然老年代如果空间不足,会发生Major GC,采用标记整理算法(老年代的对象大部分都是经过一段Minor GC的,所以相对比较稳定,每次回收的对象相对比较少,所以采用标记整理算法最合适)。
​ 另外,一个对象的创建过程,上述描述只是一个对象的创建过程中的一个步骤中的详解,一个对象的创建,从虚拟机的角度来看,包括:遇到new指令—判断引用能否在常量池定位;检查引用能否被加载、解析、初始化过—分配内存(包括指针碰撞和空闲列表法,这一部分内容是我上面的描述)—初始化内存空间—设置对象头—执行init()方法。

5. 怎样确定一个对象为垃圾

  1. 引用计数法

    ​ 引用计数算法就是在对象中添加了一个引用计数器,当有地方引用这个对象时,引用计数器的值就加1,当引用失效的时候,引用计数器的值就减1。当引用计数器的值为0时,jvm就开始回收这个对象。

    简单的来说,在JVM中的栈中,如果栈帧中指向了一个对象,那么堆中的引用计数器的值就会加1,当栈帧这个指向null时,对象的引用计数器就减1。

    ​ 这种方法虽然很简单、高效,但是JVM一般不会选择这个方法,因为这个方法会出现一个问题:当对象之间相互指向时,两个对象的引用计数器的值都会加1,而由于两个对象时相互指向,所以引用不会失效,这样JVM就无法回收。

  2. 可达性分析法(Reachability Analysis)
    所有生成的对象都是一个称为"GC Roots"的根的子树。从GC Roots开始向下搜索,搜索所经过的路径称为引用链(Reference Chain),当一个对象到“GC Roots”没有任何引用链可以到达时,就称这个对象是不可达的(不可引用的),也就是可以被GC回收了。

可达性分析法

6. 常用的垃圾回收算法有哪些?有什么优缺点

  1. **标记-清除 **

    ​ 分为两个阶段:标记和清除。根据根节点可达分析哪些对象为垃圾,并对垃圾进行标记,然后统一回收。这是最基础的算法,后续的收集算法都是基于这个算法扩展的。

    不足:

    • 扫描整个堆内存,耗时,效率低;

    • 标记清除之后会产生大量碎片。

  2. 标记整理

    ​ 分为两个阶段:标记和整理。根据根节点可达分析哪些对象为垃圾,并对垃圾进行标记,将还在被使用的对象移动到一端。然后在清理掉这个范围之外的垃圾。

    优点:

    • 避免了内存碎片

    缺点:

    • 整理内存耗时
  3. 复制

    ​ 将内存按容量划分为大小相等的两块,每次只使用其中一块,当这一块内存用完,将还在被使用的对象复制到另一块上,再将已使用过的那一块内存空间全部清理掉。

    优点:

    • 效率高,实现简单

    缺点:

    • 内存空间利用率只用50%

7. 简述你对吞吐量和停顿时间的理解

​ 在实践活动中,我们通过最优吞吐量和最短停顿时间来评价jvm系统的性能:

吞吐量越高算法越好
暂停时间越短算法越好
​ 首先让我们来明确垃圾收集(GC)中的两个术语:吞吐量(throughput)和暂停时间(pause times)。 JVM在专门的线程(GC threads)中执行GC。只要GC线程是活动的,它们将与应用程序线程(application threads)争用当前可用CPU的时钟周期。简单点来说,吞吐量是指应用程序线程用时占程序总用时的比例。例如,吞吐量99/100意味着100秒的程序执行时间应用程序线程运行了99秒,而在这一时间段内GC线程只运行了1秒。
术语”暂停时间”是指一个时间段内应用程序线程让与GC线程执行而完全暂停。例如,GC期间100毫秒的暂停时间意味着在这100毫秒期间内没有应用程序线程是活动的。 如果说一个正在运行的应用程序有100毫秒的“平均暂停时间”,那么就是说该应用程序所有的暂停时间平均长度为100毫秒。同样,100毫秒的“最大暂停时间”是指该应用程序所有的暂停时间最大不超过100毫秒。

8. 常见的jdk命令和工具有什么?并简述一下他们的作用

​ 常见的jdk命令:

  • jps

    jps是JVM Process Status Tool的简称,用于显示指定系统内所有的HotSpot虚拟机进程。常用的命令有:

    jps -l //用于输出主类的全名,如果运行的是jar包,则输出jar路径;

    jps -v //用于输出虚拟机启动时的JVM参数。

    [qianfg@Centos7 ~]$ jps -l
    6563 eurekaserver-0.0.1-SNAPSHOT.jar
    6564 manage-0.0.1-SNAPSHOT.war
    6565 mybank-0.0.1-SNAPSHOT.war
    6567 overseas-0.0.1-SNAPSHOT.war
    5639 sun.tools.jps.Jps
    17898 org.apache.rocketmq.namesrv.NamesrvStartup
    17900 org.apache.rocketmq.broker.BrokerStartup
    22783 org.apache.catalina.startup.Bootstrap
    
  • jstat

    jstat是JVM Statistics Monitoring Tool的简称,用于显示本地或远程虚拟机进程中的类加载、内存、垃圾回收、JIT编译等运行时数据。

    jstat -class pid //类装载信息

    [qianfg@Centos7 ~]$ jstat -class 6563
    Loaded  Bytes  Unloaded  Bytes     Time
     11234 19528.8        0     0.0      60.17
    
  • jinfo

    jinfo是Configuration Info for Java的简称,用于显示虚拟机各项参数。常用的命令有:

    jinfo -flag pid //用于查看未被显示指定的参数的默认值;

    jinfo -syspros pid //用于输出虚拟机进程的System.getProperties()的内容。

    [qianfg@Centos7 ~]$ jinfo -flag InitialHeapSize 22783
    -XX:InitialHeapSize=62914560
    
  • jmap

    jmap是Memory Map for Java的简称,用于生成堆转储快照文件、查询finalize执行队列、Java堆和永久代的详细信息,需要配合具体的选项参数使用。

    [qianfg@Centos7 ~]$ jmap -heap 22783
    Attaching to process ID 22783, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.221-b11
    
    using thread-local object allocation.
    Parallel GC with 2 thread(s)
    
    Heap Configuration:
       MinHeapFreeRatio         = 0
       MaxHeapFreeRatio         = 100
       MaxHeapSize              = 994050048 (948.0MB)
       NewSize                  = 20971520 (20.0MB)
       MaxNewSize               = 331350016 (316.0MB)
       OldSize                  = 41943040 (40.0MB)
       NewRatio                 = 2
       SurvivorRatio            = 8
       MetaspaceSize            = 21807104 (20.796875MB)
       CompressedClassSpaceSize = 1073741824 (1024.0MB)
       MaxMetaspaceSize         = 17592186044415 MB
       G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage:
    PS Young Generation
    Eden Space:
       capacity = 18350080 (17.5MB)
       used     = 14596944 (13.920730590820312MB)
       free     = 3753136 (3.5792694091796875MB)
       79.54703194754464% used
    From Space:
       capacity = 1572864 (1.5MB)
       used     = 131072 (0.125MB)
       free     = 1441792 (1.375MB)
       8.333333333333334% used
    To Space:
       capacity = 1572864 (1.5MB)
       used     = 0 (0.0MB)
       free     = 1572864 (1.5MB)
       0.0% used
    PS Old Generation
       capacity = 29884416 (28.5MB)
       used     = 19405328 (18.506362915039062MB)
       free     = 10479088 (9.993637084960938MB)
       64.93460671943531% used
    
    16678 interned Strings occupying 1501192 bytes.
    
  • jstack

    jstack是Stack Trace for Java的简称,用于显示当前虚拟机内每一条线程正在执行的方法堆栈集合,可用于分析线程长时间卡顿的原因。

    [qianfg@Centos7 ~]$ jstack 22783
    2020-03-12 02:48:06
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
    
    "Attach Listener" #51 daemon prio=9 os_prio=0 tid=0x00007ff7fc007000 nid=0x1bbe waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "http-nio-8080-exec-15" #50 daemon prio=5 os_prio=0 tid=0x00007ff808026000 nid=0x3c29 waiting on condition [0x00007ff7f01c1000]
       java.lang.Thread.State: WAITING (parking)
    ...此处多行省略
    "VM Thread" os_prio=0 tid=0x00007ff824074000 nid=0x5903 runnable
    
    "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007ff82401f800 nid=0x5901 runnable
    
    "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007ff824021000 nid=0x5902 runnable
    
    "VM Periodic Task Thread" os_prio=0 tid=0x00007ff8240c5800 nid=0x590a waiting on condition
    
    JNI global references: 212
    
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352

推荐阅读更多精彩内容

  • 转载blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile阅读 5,358评论 1 56
  • JVM架构 当一个程序启动之前,它的class会被类装载器装入方法区(Permanent区),执行引擎读取方法区的...
    cocohaifang阅读 1,658评论 0 7
  • 第二部分 自动内存管理机制 第二章 java内存异常与内存溢出异常 运行数据区域 程序计数器:当前线程所执行的字节...
    小明oh阅读 1,147评论 0 2
  • 介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明 程序计数器:看做当前线程所执行的字节码行号指示器...
    jemmm阅读 2,228评论 0 9
  • 作者:一字马胡 转载标志 【2017-11-12】 更新日志 日期更新内容备注 2017-11-12新建文章初版 ...
    beneke阅读 2,197评论 0 7