JVM知识扫盲篇

简介: JVM知识扫盲篇

JVM扫盲

三:总结提升

一:故事背景

最近在回顾JVM的基本知识,今天在这里总结一下,JVM的基础知识。方便之后再次进行回顾。


二:知识点主要构成

2.1 JVM为什么能跨平台

1.JVM类似于软件。不同系统上的JVM是不一样的,但是却提供了相同的功能。

2.JVM执行的是字节码文件,也就是.java 编译后生成的.class 文件。这样做的好处是可以很好的提高执行效率。

2.2 JVM整体结构

jvm整体结构宏观如下,每一部分我都进行了表明,下面将会详细讲解,每一部分的作用。

2.1 类加载子系统

2.1.1 概述

类加载子系统主要分为三个步骤,分别是 加载、链接、初始化。其中链接最为重要。链接主要分为三个部分,分别是 验证、准备、解析。这里重点解释一下什么叫做:“将符号引用解析为直接引用”。

在Java里,Java类和其成员都表示为 符号引用。不涉及到具体的内存地址或者方法指针。当Java程序在JVM上运行的时候,符号引用要被解析为直接引用,以便在运行的时候可以正确的找到对应的类、方法、字段。

2.1.2 具体类加载器

Java中提供的类加载器主要分为 2类四种。


1.引导类加载器

引导类加载器(BootStrapClassLoader),一般由C或者C++语言编写,直接与操作系统交互,我们一般不对齐进行操作


2.自定义类加载器

Java提供了2中自定义类加载器,通过实现(ClassLoader类)进行实现,分别是 ExtClassLoader、APPClassLoader、加载器。不同的类加载器负责加载不同的目录。

2.1.3 双亲委派机制


作用:避免类重复加载、防止核心API被篡改。

概述:加载类的时候,先提交给其父类进行类加载。一直提交给 BootStrapClassLoader,如果都无法加载指定类,才由自己进行加载。

2.1.4 Tomcat为什么要自定义类加载器

JVM判断一个类是不是已经加载的逻辑是:类名+对应的类加载器实例

如果Tomcat直接使用APPClassLoader类进行加载类的话,会出现多个项目中同名的类无法进行加载的情况。


例如我们有项目A和项目B,项目A内有一个类其全称为com.test.Hello.class,项目B中同样有一个类为com.test.Hello.class。如果使用同一个APPClassLoader,会导致只能加载一个的情况。Tomcat针对这种情况为每个应用都设置了自己单独的类加载器 WebappClassLoader 这样两个应用中的Hello.class类都会分别进行加载,不会产生冲突。


2.2 运行时数据区

2.2.1 整体概念

根据上面颜色的不同,将其分成了线程共享和线程隔离的两大部分。其中方法区和堆是多个线程共享的。

方法栈和本地方法栈,程序计数器。都不会被多个线程共享。每个线程独立的进行管理,管理自己的方法的调用过程。


2.2.2 程序计数器的作用

1.PC Register,程序计数寄存器,建成程序计数器。它是物理寄存器的抽象实现。用来记录待执行的下一条指令的地址。

2.其实程序控制流的指示器,循环、if else、异常处理、线程恢复,都依赖其完成。

2.2.3 虚拟机栈(Java栈、Java方法栈)

java方法执行的过程中,不停的将方法对应的栈帧压入栈中。执行完之后,将会将栈帧进行出栈。

什么是栈帧:
局部变量表存储了定义的每个变量。

操作数栈用来记录要进行操作的数。

这里给一个小例子,用来方便理解操作数栈

public static void main(String[] args) {
  int a = 10;
  int b = 20;
  int c = a+b;
}

在执行操作的时候,会先将树放到操作数栈内,然后根据不同的指令将操作数放入到局部变量表,不同的变量具体对应的变量内。


2.2.4 本地方法栈

概念:

在Java中定义,但是由其它语言实现的方法。例如:native method方法。


2.2.5 堆以及堆中的各个区域作用

2.2.5.1 概念:

JVM规范中规定所有的对象和数组都该存放在堆中,在执行字节码指令时,将创建的对象存入堆中,对象对应的引用地址存入虚拟机栈中的栈帧中。

当方法执行完之后,创建的对象不会马上回收,而是等到jvm后台执行GC后,对象才会被回收。

2.2.5.2 堆内存设置:

-Xms:(memory start),用来指定初始化内存的大小。

-Xmx:(memory max),指定堆的最大内存大小。

一般会把 -Xms和-Xmx的值设置为一样,这样Jvm在GC之后,就不需要去修改堆内的内存大小了

我们可以自己实践来查看指定的堆的大小

启动jar包:

java -XX:NativeMemoryTracking=summary -Xms1024m -Xmx1024m -jar  jar包路径 

使用jcmd命令查看

//1.jcmd 查看进程号
jcmd 
//2. 根据进程号查看堆的使用情况
jcmd 进程id VM.native_memory summary

2.2.5.3 堆初始化大小:

初始化内存大小:物理内存/64

最大内存大小:物理内存/4

2.2.5.4 新生代与老年代

新生代存放的是刚刚创建的对象

老年代存放的是经过多次GC之后,仍然存在的对象

新生代与老年代默认的比例为 1:2 ,一遍不需要调整,除非明确知道存活时间较久的对象更多,则需要调大老年代占比。

2.2.5.5 对象流转过程


新生代分为三块区域,分别是 Eden、S0、S1。三块区域,新对象创建出来,会先放到Eden区内,当进行一次Youg GC之后,剩余的对象将会转移到S0,并且增加一个GC次数的表示。在阈值到达之前,都会在S0-S1,反复转移。知道达到GC的阈值,才会进入老年代。


如果创建的大对象,从Eden区域出来之后,无法放入 S0,S1,区域,对象在经历过一次GC之后,将会直接进入老年代。


如果创建的是超大对象,无法放入Eden区的话,创建的对象将会直接存入老年代。

2.3 垃圾回收

2.3.1 概念

垃圾指的是JVM中,没有任何引用指向它的对象。如果不清理这些垃圾对象,那么它们就会一直占用内存,而无法给其他对象使用,最终垃圾对象越来越多,直到OOM。


2.3.2 寻找垃圾对象方法


引用计数法:

每个对象都保存一个引用计数器属性,用户记录对象被引用的次数。

实现起来简单,但是需要额外的空间来存储引用数,维护引用数。并且无法处理循环引用问题。


可达性分析法:

从GCRoot开始,寻找到可达对象,不可达的就是失去引用的对象。


GCRoot:

正在执行的方法的参数、局部变量引用的对象

本地方法栈正在执行的方法的参数、局部变量所对应对象的引用

方法区中保存的类的静态属性对应的对象引用

方法区中保存的类信息中的常量属性对应的对象引用

2.3.3 垃圾回收算法

标记-清除算法:

  • 非常基础,常用的垃圾回收算法。分为两个阶段。
  • 标记阶段:从GCRoot 开发遍历,找打可达对象,并且在对象头中标记
  • 清除阶段:堆内存空间进行线性遍历,如果发现对象头中未标记为可达对象,则进行回收
    存在问题:效率不高,会产生内存碎片问题。由于回收过后,内存是不连续的,新加入的大的对象可能无法存放

复制算法:


将内存空间分为两块,每次使用其中一块,在进行垃圾回收时,将可达对象复制到没有被使用的内存块中,然后再清除当前内存块的对象。后续按照相同的流程进行垃圾回收。

这种算法解决了标记清除算法,存在的碎片问题。

如果可达对象比较多,垃圾对象少,复制算法效率就比较低。其适合新生代的垃圾回收。

始终有一半空间是空闲的。可能需要频繁修改栈内引用指向的堆内对象的地址。

标记整理算法:

  • 结合了标记清除和复制算法的优点。首先标记可达对象,将所有存活对象移动到内存的一段,最后清理边界外所有空间
    算法对比:
- 标记-清除 标记-整理 复制
速度 中能 最慢 最快
空间开销 少(有碎片) 少(无碎片) 最多
移动对象

2.3.4 常见的垃圾回收器

三:总结提升

本文总结了Java的JVM虚拟机的整体结构,以及各个结构对应的大概功能,此文章正如标题所说,是属于扫盲篇。希望大家看完之后,能对整个JVM的整个结构,各个结构功能有想应的了解。如果大家感兴趣,还请持续关注我,接下来会更新一些JVM其它相关知识。

目录
相关文章
|
安全 Java
JVM知识点扫盲系列(1)
每次young gc的时间,和eden空间的大小是正比关系吗? 在进入公司之后,这个问题先后被多次问到,那young gc的时间到底和哪些因素有关呢? 来看一段代码,逻辑很简单,不断的分配1M的大小,直到触发YGC。
1009 0
|
2月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
38 4
|
4月前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
|
18天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
16天前
|
Java Linux Windows
JVM内存
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制。
16 1
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
72 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
2月前
|
存储 缓存 算法
JVM核心知识点整理(内存模型),收藏再看!
JVM核心知识点整理(内存模型),收藏再看!
JVM核心知识点整理(内存模型),收藏再看!
|
2月前
|
存储 算法 Java
聊聊jvm的内存结构, 以及各种结构的作用
【10月更文挑战第27天】JVM(Java虚拟机)的内存结构主要包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和运行时常量池。各部分协同工作,为Java程序提供高效稳定的内存管理和运行环境,确保程序的正常执行、数据存储和资源利用。
50 10
|
2月前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
2月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
55 2