当前位置: 首页 > 科技观察

技术干货:JVM架构体系和GC命令全面梳理,推荐收藏

时间:2023-03-17 23:53:16 科技观察

JVM运行时资料区概述Java虚拟机Java虚拟机(JVM)是??一种物理机的软件实现。java编译器javac将源代码文件.java编译成字节码文件.class,然后将这个字节码文件.class放入JVM中,加载并执行字节码文件.class。JVM架构图如下。JVMArchitectureJVM架构体系垃圾收集(garbagecollection):负责回收堆内存heap中未使用的对象判断对象是否存活,可达性检测引用计数算法:为对象添加一个引用计数器,每当有地方引用it,计数器值加1,当引用失效时,计数器值减1。任何时候计数器为0的对象就是不能再使用的寻根算法:通过一系列名为“GCRoots”的对象为起点,从这些节点开始向下搜索,搜索所经过的路径称为引用链,当一个对象没有任何引用链连接到GCRoots时,证明该对象不可用.垃圾收集算法mark-clearalgorithmMark-Sweep:先标记所有需要回收的对象,标记完成后统一回收所有对象标记对象效率问题:标记和清除动作不是高效的动作空间问题:标记和清除之后清除,产生大量不连续的内存碎片。太多的碎片导致在分配大对象时无法找到足够的连续内存而不得不提前触发另一个。一次性gc复制算法Copying:将可用内存按照容量分成两块大小相等的,每次只使用其中一块。当本块内存用完后,将存活的对象复制到另一个块中,然后对已用内存空间进行一次清理,可用内存减少为原来的一半。被复制,一些生命周期长的对象来回复制多次,耗费大量时间->分代收集解决这个问题分代收集算法:根据对象的生命周期将内存分成若干份Blocknewgeneration:内存分为一个较大的Eden空间和两个较小的Survivor空间。在Eden中创建新的对象,当Eden满时,触发YGC,将Eden中存活的对象移至S0区,Eden被清除;当Eden满载YGC时,将Eden和S0中的存活对象复制到S1中(复制算法保证S1来自Eden和S0中的存活对象占据连续的内存空间,避免碎片化);清除Eden和S0。下一轮,S0和S1交换角色,如此循环。如果对象的副本数达到15次,则对象将被送往老年代。老年代:对象存活率高垃圾收集器(垃圾收集算法的具体实现)并行与并发并行:指多个垃圾收集线程并行工作,但此时用户线程仍处于等待状态收集线程执行同时,用户程序继续运行,垃圾回收程序在另一个CPU上运行年轻代minorgc:新生代的内存不是很大,minorgc的回收速度一般更快老年代majorgc/fullgc:Oldgeneration内存一般比较大,用来缓存大对象,所以回收速度是minorgc的10倍左右。Throughput吞吐量:JVM一共运行100分钟,垃圾回收耗时1分钟,所以吞吐量为99%,即(all-gc)/all(对于batchpipeline)Pausetime:垃圾回收器运行时,应用程序的暂停时间(针对流式管道)收集器类型NEWserial,单线程parNew,serial多线程版本ParallelScavenge,replicationalgorithm,Inparallel,优先保证吞吐量,不管用户的STW体验如何,系统在吞吐量方面进行了优化,较长的停顿时间是可以接受的。OLD/tenuredSerialOld,老版本Serial收集器,单线程,标记排序算法ParallelOld,老版本ParallelScavenge收集器,多线程,标记排序算法ConcurrentMarkSweep,CMS:优先恢复停顿时间最短,用户体验好,mark-sweepalgorithmNEWandOLD重点:region内存划分,优先region恢复方式。优先回收价值最大的区域垃圾,G1:它将整个Java堆划分为多个大小相等的独立区域(Regions)。虽然仍然保留了新生代和老年代的概念,但是新生代和老年代不再是物理上孤立的,它们都是Region(不一定是连续的)集合的一部分。类加载子系统(classloadersub-system):定位并导入二进制类文件,验证导入类的正确性,为类变量分配和初始化内存,解析符号引用并启动类加载器bootstrapclassloader,负责在JAVA_HOME/lib扩展下加载classloader扩展类加载器,负责加载JAVA_HOME/lib/ext下合法的类文件;applicationclassloader,负责加载用户路径classpath下合法的class文件;用户定义的类加载器,classMyClassLoaderextendsClassLoaderJVM通过双亲委派模型加载类,先交给它的最低级父类加载,只有当父类加载不出来时才尝试加载。if(parent!=null)parent.loadclass(name)recursive递归,applicationclassloader->extensionclassloader->bootstrapclassloader首先检查用户定义的classloader是否被缓存,如果有缓存则直接返回,如果没有则delegate父类加载器去加载,如果父类已经缓存了,则直接返回,否则委托给父类加载器;直到最后一个bootstrapclassloader,如果找不到缓存,就在它的路径下查找,如果找到,就返回二级,否则就到它的子类Return,让它的子类在它的路径下找到;最后返回自定义类加载器,找不到则抛出异常执行引擎:执行类加载器中的方法指令解释器解释器:读取源码或word段代码,直接一一执行(javac在外JVM)Just-In-Timecompiler/JIT:读取源代码,更多的是字节码,然后编译成机器码,执行Java虚拟机,就是假想的可以运行Java代码的计算机。java源文件(.java)通过java编译器javac生成字节码文件(.class),字节码文件(.class)翻译成具体的机器码在机器上就是sourcecode/sourcecode/Sourcecode/.java->bytecode/Bytecode/.class->machinecode/Machinecode/nativecode/NativeCoderuntimedataareas:JVM在运行时,需要从整个计算机内存中划出一块内存区域来存放东西jvm需要使用。定义对象引用(这些都存放在各个线程的JVMStack中),这是gc的主要回收区。MethodArea/PermanentGeneration:JVM内部共享/线程间共享,保存各个类的信息(类名、Field信息、方法信息)类、静态变量static等。ProgramcounterProgramCounterRegister/PCregister:线程内共享,保存各个线程正在执行的虚拟机字节码指令的地址;如果方法是Native,则计数器为空UndefinedvirtualmachinestackJVMStack/threadstack:线程内共享,保存基本数据类型对象和自定义对象的引用,执行环境的contextual本地方法栈stack为virtual服务机器执行Java方法(即字节码),而本地方法栈为虚拟机执行的Native方法服务。垃圾收集器启动命令行newgenerationgcmodeoldgenerationgcmode-XX:+UseSerialGCserialserialcollectorserialOldserialcollector-XX:+UseParNewGCparNewparallelcollectordefault-XX:+UseParallelGCparallelparallelcollectordefault-XX:+UseParallelOldGCdefaultparallelparallelcollector-XX:+UseConcMarkSweepGCdefaultCMSparallelcollector-XX:+UseG1GCG1collectorG1收集器按照上表中新生代和老年代的gc模式相互协作。默认垃圾收集器,Java7-并行GCJava8-并行GCJava9-G1GC