JVM分享

JVM分享

官网:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

Java代码的执行流程

我们编写完之后的java文件如果要运行,java文件会编译成class文件,在jvm中运行时ClassLoader会加载class文件,加载进来之后,就到了运行时数据区之中。

Field Descriptors 字段描述符

Method Descriptors 方法描述符

JVM运行时数据区

在官网的2.5. Run-Time Data Areas章节

2.5.1. The pc Register

pc计数器存放的是当前正在执行的指令的地址。

2.5.2. Java Virtual Machine Stacks

当我们创建一个线程时,会创建一个jvm虚拟机栈,调用执行任何方法都会给对应方法创建栈帧,然后入栈,当程序发生异常时(经典异常:StackOverflowError),异常信息就是从虚拟机栈中打印出来了。存放了各种基本数据类型、对象引用。

2.5.3. Heap

堆是所有jvm线程共享的,堆也是是运行时数据区,从中分配所有类实例和数组的内存。堆在虚拟机启动时创建,GC可以回收堆内存。同时创建的对象也存放在堆中。所以在堆中最常见的异常就是OutOfMemoryError

2.5.4. Method Area

方法区也是所有jvm线程共享的,方法区类似于常规语言的编译代码的存储区域,里面存放的是每个类class的结构,例如运行时常量池,字段和方法数据,以及方法和构造函数的代码。1.8之前的jdk版本,Metaspace是永久代(堆内),从1.8版本开始。永久代被移除,新增了Metaspace,Metaspace使用的是本地内存。

2.5.5. Run-Time Constant Pool

常量池用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

2.5.6. Native Method Stacks

本地方法栈与虚拟机栈所发挥的作用非常相似,他们之间的区别不过是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机中使用到的native方法服务。

JVM的内存结构

jvm1.8中内存主要分为两大区域,堆与非堆。

堆是Heap,非堆也就是Metaspace。然后堆又分为两部分,YoungOld 区。Young 中又分为两部分,分为EdenSurvivorSurvivor区又分为From Survivor空间也就是俗称的S0和 To Survivor空间也就是S1。

S0跟S1大小是相同的,并且同一时间只有一个是开启的,另外一个是空的。正常来说,新生成的对象首先放到年轻代Eden区,当Eden空间满了,触发第一次Minor GC,存活下来的对象移动到S0区,S0区满后再触发一次 GC,S0区存活对象移动到S1区,这样保证了一段时间内总有一个survivor区为空。然后每进行一次GC,对象的age就会+1,age到了15(也就是MaxTenuringThreshold 从年轻代到老年代的晋升次数的最大值)之后,对象就会进入老年代。

非堆也就是Metaspace,他也分为两部分,一个是ccs(Compressed Class Space),另一个是CodeCache。

指针有短指针32位跟长指针64位,ccs开启之后才会在Metaspace中存在,并且会用32位的短指针代替64位的长指针。堆中的对象都有一个指向自己class的指针,而class是在Metaspace中,在64位环境中指针一般是64位,有时候为了提高性能会启用ccs,将指针压缩成32位。

CodeCache它主要用于存放JIT(即时编译)所编译的代码,编译了就会存在,没有就不会。

Java mixed mode

Java的混合模式,Java既是解释型(int)又是编译型(comp)语言。

JVM参数类型

  1. 标准参数,标准参数是稳定的java参数,一般不会随着版本的升级出现变化,常见的有version help classpath cp等。

  2. X参数,随着版本相对变化较少,最经典的参数 -Xint -Xcomp。java -Xint -version java -Xcomp -version

  3. XX参数,随着版本变化较大,参数又分为boolean跟非boolean类型。

    a.boolean -XX: [+/-] name

    例:-XX:+UseG1GC / -XX:-UseG1GC

    b.非boolean -XX: name = value

    例:-XX:MetaspaceSize=128m

    -XX:SurvivorRatio=8

    -XX:NewRatio=2

    -XX:MaxTenuringThreshold=15

PrintFlags系列参数

java -XX:+PrintFlagsInitial

-XX:+PrintFlagsInitial-XX:+PrintFlagsFinal,= 表示默认值,:=表示修改过的

几个特殊的XX参数:

-Xms:表示min, 是 -XX:InitialHeapSize的简写

-Xmx:表示max,是-XX:MaxHeapSize的简写

-Xss 是-XX:ThreadStackSize

-XX:InitialHeapSize=268435456 ≈ 268M 1/64个内存大小

-XX:MaxHeapSize=4294967296 ≈ 4.2G 1/4个内存大小

垃圾回收

1.确定会被回收的对象,两种方式

​ 1:引用计数,在堆中存储对象时,在对象头处维护一个counter计数器,如果一个对象增加了一个引用与之相 连,则将counter++。如果一个引用关系失效则counter--。如果一个对象的counter变为0,则说明该对象已经 被废弃,不处于存活状态。

​ 2:枚举根节点可达性分析

​ 常说的GC(Garbage Collector) Roots,特指的是垃圾收集器(Garbage Collector)的对象,GC会收集那些不是GC Roots且没有被GC Roots引用的对象。

一个对象可以属于多个root,GC Roots有以下几种:

  • Class - 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的Java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots,.
  • Thread - 活着的线程
  • Stack Local - Java方法的local变量或参数
  • JNI Local - JNI方法的local变量或参数
  • JNI Global - 全局JNI引用
  • Monitor Used - 用于同步的监控对象
  • Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并没有为这些对象提供其它的信息,因此需要去确定哪些是属于"JVM持有"的了。

2.GC算法

标记-清除 Mark-Sweep

​ 1.标记,从GC Root开始找,找出存活的对象

​ 2.清除,将没有标记的对象清除

​ 缺点是内存碎片太多

复制 Copy

​ 内存划分成两个区域,同一时间点只有一个是活动的,GC线程会将活动区域的存活对象全部复制到空闲区域,并对内存地址排序,新生代GC使用较多,缺点是浪费一般内存。

标记-整理 Mark-Compact

​ 1.标记

​ 2.整理,不直接对可回收对象进行清理,而是让所有可用的对象都向一端移动。然后直接清理掉边界以外的内存。

​ 在标记-清除的算法基础上,增加了清除后对内存地址的排序整理

分代

​ 根据堆中不同的区域使用不同的算法,新生代使用复制算法,老年代使用标记清楚/标记整理

相关推荐
吾日三省吾码2 小时前
JVM 性能调优
java
弗拉唐3 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi773 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3434 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀4 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20204 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深4 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
shuangrenlong4 小时前
slice介绍slice查看器
java·ubuntu
牧竹子4 小时前
对原jar包解压后修改原class文件后重新打包为jar
java·jar