JVM
概念
JVM :Java virtual machine,是Java程序运行的基础,基于不同的操作系统,将字节码转换为机器码,进而管理并运行。主要有三个组件:
- 类加载器(classLoader):将编译后的字节码文件加载到jvm中,转换为jvm可以识别的对象。
- 运行时数据区(runtime data area):jvm在Java程序执行时所使用的内存空间,包括方法区(method area)、栈(stack)、堆(heap)、本地方法栈(native method stack)、程序计数器(pc)。
1、方法区:存储已经被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等。
2、栈:又称方法栈,被线程私有,线程执行都会建立一个栈用于存储局部变量表,操作站,动态链接,方法出口等。
3、本地方法栈:执行native方法的栈,类似栈。
4、堆:内存管理中最大的一块,被线程共享,几乎所有的对象都存在这。当空间不足会出现oom异常,根据对象的存货周期不同,jvm将对象进行分代管理,由垃圾回收器进行回收管理。
5、程序计数器:保存当前线程执行的字节码位置,每个线程工作都有独立计数器。
JMM:Java Memory Model,Java内存模型,描述了线程之间的内存关系,分为主内存(线程共享的内存,用于存储Java对象和变量的值)和工作内存(线程私有的的内存空间,存储Java对象的和变量的副本)
类加载和卸载
过程
- 加载阶段:类加载器在类路径找到指定的Java类文件,加载到jvm中,然后转换成class对象。
- 验证阶段:确保符合jvm类的格式
- 准备阶段:验证之后,进行内存分配,静态变量分配默认值
- 解析阶段:对类中的符号引用(方法、接口、子段)进行解析
- 初始化阶段:对静态块和静态变量进行初始化
- 使用阶段:类的实例化
- 卸载:GC
类加载器
-
Bootstrap ClassLoader:也称为根加载器,是JVM内置的类加载器,用于加载Java核心类库,例如java.lang、java.util等。
-
Extension ClassLoader:也称为扩展类加载器,用于加载Java的扩展类库,例如javax等。它负责加载JVM扩展目录($JAVA_HOME/lib/ext)中的类和用户自定义的类库,它本身是由Bootstrap ClassLoader加载的。
-
Application ClassLoader:也称为应用程序类加载器,用于加载应用程序中的类文件。
加载机制
双亲委派机制:加载器加载类时先把请求委托给自己的父类加载器执行,直到顶层的启动类加载器。父类加载器能够完成加载则成功返回,不能则子类加载器才自己尝试加载。
优点:
1、避免类的重复加载
2、避免Java的核心api被篡改
分代回收
分代回收是jvm中的一种垃圾回收策略,根据对象不同的生命周期将他们划分成不同的代,在此基础上采用不同的策略进行垃圾回收。
主要分为:
- 新生代:新创建的对象,大部分生命周期很短,很快就会被回收。
复制算法:将内存分为两个区域,当一个满时,将存活的对象赋值到另一个区域,保证了每次都有一半内存可以使用, 但是只能使用一半了。
- 老年代:经历了多次的垃圾回收依然存在内存中,生命周期较长。
标记清除:标记所有存活的对象,然后清除剩余的,会产生大量的内存碎片。
标记整理:标记所有存活的对象,将他们往一端移动,剩余的删除。这样可以避免了内存碎片的产生,但是移动对象造成很大的开销。
- 永久代:存放java类名、方法名、字段名、访问修饰等。
G1
G1垃圾回收器将堆内存划分为多个大小相等的区域(Region),每个区域的大小可以在启动时指定,一般为1MB到32MB之间。G1垃圾回收器采用了分代回收的思想,将堆内存分为新生代和年老代。不同的是,G1垃圾回收器中的年老代并不是像传统的垃圾回收器那样只是一块连续的内存区域,而是由多个大小不等的区域组成。G1垃圾回收器会动态地调整每个区域的大小和年代,根据垃圾对象的分布情况来优化回收性能。
FullGC
Full GC(Full Garbage Collection)是Java虚拟机中的一种垃圾回收操作,是对整个Java堆进行垃圾回收的过程,包括新生代和年老代。与之相对的是Young GC(Young Generation Garbage Collection),它只回收新生代的垃圾对象。
触发
-
当Java堆空间不足时,虚拟机会进行Full GC,以尽可能地回收垃圾对象,释放内存空间。
-
当程序调用System.gc()方法时,虚拟机会进行Full GC,以回收垃圾对象,释放内存空间。
-
当发生永久代空间不足的情况时,虚拟机会进行Full GC,以回收永久代中的垃圾对象。
Java对象
结构
-
对象头:对象头包含两部分信息,一部分是用于存储对象自身的运行时数据,另一部分是用于存储类型指针。其中运行时数据包括:对象的哈希码、锁状态标志、线程持有的锁、偏向锁线程ID等信息。类型指针指向对象所属的类的元数据信息,即Class对象。
-
实例数据:实例数据是对象实际存储的数据,包括对象的成员变量和数组元素等。
判断回收
判断存活
- 引用计数:新增引用时加一,反之减一,为0时可以回收
- 可达性分析:从GC root向下搜索,走过的路径为引用链。没有链的即可以回收。
调优
命令
-Xms:设置Java堆内存的初始大小。例如:-Xms1g表示初始堆大小为1GB。
-Xmx:设置Java堆内存的最大大小。例如:-Xmx2g表示最大堆大小为2GB。
-Xmn:设置新生代的大小。例如:-Xmn256m表示新生代大小为256MB。
-XX:MaxPermSize:设置永久代的最大大小。例如:-XX:MaxPermSize=256m表示永久代最大为256MB。
-XX:SurvivorRatio:设置新生代中Eden区和Survivor区的比例。例如:-XX:SurvivorRatio=8表示Eden区和Survivor区的比例为8:1。
-XX:NewRatio:设置新生代和老年代的比例。例如:-XX:NewRatio=2表示新生代和老年代的比例为1:2。
-XX:MaxTenuringThreshold:设置对象在新生代中经过多少次垃圾回收后晋升到老年代。例如:-XX:MaxTenuringThreshold=15表示对象在新生代中经过15次垃圾回收后晋升到老年代。
-XX:+UseConcMarkSweepGC:使用并发标记清除垃圾回收器。
-XX:+UseParallelGC:使用并行垃圾回收器。
-XX:+UseG1GC:使用G1垃圾回收器。
工具
jstat:jstat是JDK自带的命令行工具,用于监控JVM内存、垃圾回收、类加载等信息。
jvisualvm:jvisualvm是JDK自带的图形化工具,可以监控JVM内存、CPU、线程等信息,并提供线程快照、堆转储等功能。
jmc:jmc(Java Mission Control)是JDK自带的商业级性能监控工具,可以对JVM进行全面的监控和调优,包括CPU、内存、线程、垃圾回收等方面的性能分析。
JProfiler:JProfiler是一款商业级的Java性能分析工具,支持对JVM的CPU、内存、线程、垃圾回收等方面进行监控和分析,并提供了丰富的报表和图形化界面。
YourKit:YourKit是一款商业级的Java性能分析工具,支持对JVM的CPU、内存、线程、垃圾回收等方面进行监控和分析,具有较高的性能和可扩展性。
其他
元空间
JDK 8之前,Java虚拟机将类型信息、常量等信息存储在永久代(PermGen)中,这些信息随着应用程序的启动而加载,并且会在运行时不断地进行更新,导致PermGen区域容易发生内存溢出。
为了解决这个问题,JDK 8引入了元空间(Metaspace),将类型信息、常量等信息从永久代中移动到了元空间中,从而避免了永久代内存溢出的问题。
元空间和永久代最大的区别是,元空间不再使用JVM堆内存,而是使用本地内存。元空间的大小可以动态地增长或缩小,这样就可以避免了由于永久代大小固定而导致内存溢出的问题。同时,元空间还可以通过参数进行调优,例如设置元空间的大小、最大大小等。
Stop the world(STW)
在Java中,当进行垃圾回收操作时,JVM会暂停所有执行线程,然后进行垃圾回收操作。这个过程可能需要花费几百毫秒甚至几秒钟的时间,这段时间内应用程序的所有线程都被暂停,直到垃圾回收完成,才会继续执行。
OopMap
OopMap(Object Map)指的是一种用于记录对象属性和类型信息的数据结构。在Java虚拟机中,每个对象都会有一个OopMap,用于记录对象的内部结构和类型信息,方便JVM进行垃圾回收、方法调用等操作。
在方法调用时,JVM会通过OopMap来获取方法参数和局部变量的值。在进行垃圾回收时,JVM会遍历所有的OopMap,查找对象的引用关系,以便找出哪些对象已经不再使用,然后进行回收。
垃圾回收器
Serial收集器:Serial收集器是一种单线程的垃圾回收器,主要用于小型应用程序或者测试环境。
Parallel收集器:Parallel收集器是一种多线程的垃圾回收器,可以提高垃圾回收效率和吞吐量,适用于需要高性能的应用程序。
CMS收集器:CMS收集器是一种基于标记-清除算法的并发垃圾回收器,可以在应用程序运行的同时进行垃圾回收,适用于需要低延迟的应用程序。
G1收集器:G1收集器是一种基于分代和区域划分的垃圾回收器,可以根据实际内存使用情况动态划分内存区域,从而提高垃圾回收效率和吞吐量。