首页 > 其他分享 >理解JVM

理解JVM

时间:2024-10-16 19:22:34浏览次数:8  
标签:对象 ClassLoader 理解 内存 JVM class 加载

文章目录


前言

JVM 内部涉及到的内容是非常广泛的。咱们主要讨论三个方面的问题:
1.JVM 内存区域划分
2.JVM 中类加载的过程
3.JVM 中的垃圾回收机制


一、JVM 内存区域划分

一个运行起来的 java 进程,其实就是一个 JVM 虚拟机。需要从操作系统中申请一大块内存,把这个内存划分成不同的内存区域。

  • 1.方法区(1.7及其之前)/ 元数据区(1.8开始)
    这里存储的内容是类对象:.class 文件加载到内存之后就成了类对象。

  • 2.
    这里存储的内容是代码中 new 出来的对象(占据空间最大的区域)

  • 3.
    这里存储的内容是代码执行过程中,方法之间的调用关系

  • 4.程序计数器
    (比较小的空间)主要存放一个“地址”,表示下一条要执行的指令在内存中的哪个地方

大家可以看下面这张图形象地展示了 JVM 中的区域划分:

在这里插入图片描述
值得注意的是:
虚拟机栈和程序计数器都是每个线程都有一份的。
而元数据区和堆在 JVM 进程中是只有一份的。
所以,一个JVM 进程可能有多个线程。每个线程都有自己的程序计数器和栈空间,这些线程共用同一份堆和元数据区(方法区)

  • 常见面试题:

下面代码中 n,a,t 处于哪个区域?

在这里插入图片描述
答:一个变量处于哪个区域,和变量的形态密切相关。Test 类中定义的变量是成员变量,在下面main 方法中new 对象时就会包含这个属性,所以成员变量处在堆上。而下面的变量a 由于加了static 修饰就是静态变量,包含在类对象中,那么静态变量就是处在元数据区(方法区)上。最后下面main 方法中的局部变量t 是一个引用类型的变量,这里存的是一个对象的地址,不是对象本身。处于栈上的局部变量表中,所以,局部变量处在栈上

二、JVM 中类加载的过程

a.类加载的基本流程(熟练背诵)

java 代码会被编译成 .class 文件(里面包含了一些字节码),java 程序要想运行起来,就需要让 jvm 读取到这些 .class文件 ,并且把里面的内容构造成类对象保存到元数据区(方法区)中。所谓的“执行代码”其实就是调用方法,要想调用方法,就要先知道每个方法编译后生成的指令都是啥,而这些指令都是存储在 .class 文件中的。

  • 类加载的5个步骤:
    1.加载:通过“全限定类名”,在一些指定的目录范围内找到 .class 文件,打开并读取文件内容
    2.验证:验证当前读到的这个格式是否符合要求。.class 文件是一个二进制的格式(某些字节都是有某些特定含义的)。
  • 3.准备:给类对象分配内存空间(最终的目标是要构造出类对象)。这里只是分配内存空间,还没有初始化,此时这个空间上的内存的数值都是0。
  • 4.解析:针对类对象中包含的字符串常量进行处理,进行一些初始化操作
    java 代码中用到的字符串常量,在编译之后,也会进入 .class 文件中。字符串常量是引用,本质上保存的是地址,在 .class 文件中不涉及内存地址,所以就会先设置成一个“文件的偏移量”,当类真正被加载到内存中的时候,再把这个偏移量替换成真正的内存地址。
  • 5.初始化:针对类对象进行初始化,把类对象中需要的各个属性都设置好。需要初始化 static 成员,需要执行静态代码块以及还可能需要加载一下父类。

b.双亲委派模型

双亲委派模型属于类加载中的第一个步骤,是“加载”过程其中的一个环节。负责根据全限定类名来找到 .class文件。

  • JVM 中内置了三个类加载器:BootStrap ClassLoader、Extension ClassLoader、Application ClassLoader

  • 类加载的过程(找 .class 文件的过程)
    1.给定一个类的全限定类名,形如 java.lang.String
    2.从 Application ClassLoader 作为入口,开始执行查找的逻辑
    3.Application ClassLoader 不会立即去扫描自己负责的目录(项目当前的目录和第三方库对应的目录),而是把查找的任务交给它的父亲—Extension ClassLoader
    4.Extension ClassLoader,也不会立即扫描自己负责的目录(JDK 中一些扩展的库对应的目录),也是把查找的任务交给它的父亲—BootStrap ClassLoader
    5.最后,BootStrap ClassLoader 只好扫描自己负责的目录(标准库中的目录)。如果能够找到,就执行后续的类加载操作,此时查找过程 也就结束了。
    6.但是,如果给定的雷不是标准库中的类,就会回到 Extension ClassLoader 来进行扫描扩展库的目录。
    7.如果还是没有扫描到,就会继续回到 Application ClassLoader 来扫描当前项目和第三方库的目录。
    8.最终,如果还是没有没找到,就会抛出一个 ClassNotFoundException 这样的异常。

在这里插入图片描述
之所以搞这一套流程,主要的目的是为了确保标准库的类被加载的优先级最高,其次是扩展库,再其次是自己写的类和第三方库

三、JVM 中的垃圾回收机制(GC)

GC就是让JVM 自行判断某个内存是否就不再使用了,如果这个内存后面确实不用了,JVM 就自动地把这个内存给回收掉。
GC 回收的目标是内存中的对象,对于 java 来说,就是 new 出来的对象

  • 在java 中,使用对象,必须要依靠引用。如果一个对象没有引用指向了,就可以视为是垃圾了。

  • GC 可以理解成两大步骤:

1.找到垃圾

有两种主流的方案:
a.引用计数(python,PHP):
new 出来的对象,单独安排一块空间,用作一个计数器来保存引用计数。当对象的引用计数为0时,此时代码中就不可能访问到这个对象,那么这个对象就可以视为是垃圾了。
存在的问题:
1.比较浪费内存
2.存在“循环引用”问题
b.可达性分析(java)
有一个/一组线程,周期性地扫描代码中所有的对象(从一些特定的对象出发,尽可能地进行访问的遍历,把所有能访问到的对象,都标记成“可达”。反之,经过扫描之后,未被标记的对象,就是垃圾了)。
可达性分析的出发点有很多,不仅仅是所有的局部变量,常量池中引用的对象,还有方法区中的静态引用类型引用的变量等等…
存在问题:可达性分析比较消耗系统资源,开销比较大

2.如何回收垃圾?

三种基本的思路:

  • 1.标记清除(简单粗暴的释放方式)
    把对应的对象直接释放掉
    在这里插入图片描述
    缺点:会产生很多的内存碎片,导致后续内存申请举步维艰。

  • 2.复制算法
    通过复制的方式把有效的对象归类到一起,再统一释放剩下的空间
    在这里插入图片描述
    缺点:内存要浪费一半,利用率不高。如果有效的对象非常多,拷贝开销就会很大。

  • 3.标记整理
    类似于顺序表进行删除时的搬运操作,让所有有效对象向一端移动。
    在这里插入图片描述
    缺点:搬运的开销仍然很大。

  • 实际上,JVM 采取的释放思路,是上述思路的结合体。

在这里插入图片描述

1)刚 new 出来的新的对象放到伊甸区,第一轮 GC 扫描,会把有效对象通过复制算法复制到幸存区中,伊甸区就可以整个释放了。
2)GC 线程会不断地继续扫描幸存区,把可达的对象拷贝到幸存区的另一部分。
3)当一个对象已经在幸存区存活过多轮GC 时,JVM 就会认为这个对象短时间内应该不会被释放掉,就会把这个对象拷贝到老年代。
4)进入老年代的对象,虽然也会被GC 扫描,但是扫描的频率就会比新生代低很多了。

注意点:
新生代中主要使用的是复制算法
老年代中主要使用标记整理

分代回收,是JVM 中回收的主要思想方法,但是在垃圾回收器具体实现的时候,可能还会有一些调整和优化


总结

我们主要了解 JVM 的三个方面:JVM 内存区域划分、JVM 中类加载的过程和 JVM 中的垃圾回收机制。

标签:对象,ClassLoader,理解,内存,JVM,class,加载
From: https://blog.csdn.net/Ashle_MIN/article/details/142963554

相关文章

  • java 查看jvm使用哪个垃圾回收器 -XX:+PrintCommandLineFlags
    java查看jvm使用哪个垃圾回收器在Java中,你可以通过查看JVM启动参数来确定使用的垃圾收集器。你可以使用java命令的-XX:+PrintCommandLineFlags参数来打印出JVM的启动配置,包括选择的垃圾收集器。例如,你可以通过以下命令运行Java应用程序来查看使用的垃圾收集器:java-XX:+PrintC......
  • 《深入理解Java异常处理:理论与实践》
    《深入理解Java异常处理:理论与实践》引言在Java编程中,异常处理是一个非常重要的概念。它帮助开发者构建健壮、可靠的程序。本文将详细介绍Java中的异常处理机制,包括异常类的层次结构、如何捕获和处理异常,以及在编程实践中的一些最佳实践。目录异常处理的基本概念Java异常类......
  • npx的使用和理解
    npxnpm从5.2版开始,增加了npx命令。它有很多用处1、不用全局安装npm包2、不用配置script直接调用项目内部安装的模块package.json如下{"name":"laspluginlesson","version":"1.0.0","description":"","main":"inde......
  • JVM第7篇-性能监控 & JVM性能调优案例
    JVM第7篇-性能监控&JVM性能调优案例性能监控一、JVM监控及诊断工具-命令行篇1.1基础故障处理工具1.1.1jps:虚拟机进程状况工具命令格式使用1.1.2jstat:虚拟机统计信息监视工具命令格式使用1.1.3jinfo:Java配置信息工具命令格式使用1.1.4jmap:Java内存映像分......
  • Python学习的自我理解和想法(13)
    学的是b站的课程(千锋教育),跟老师写程序,不是自创的代码!今天是学Python的第13天,学的内容是模块入门以及pip引入,后面估计是一天一个模块。开学了,时间不多,写得不多,见谅。目录1.模块入门2.模块导入语法(1).import(2)form模块名import方法名或变量名(3)form模块名import*......
  • Python学习的自我理解和想法(10)
    学的是b站的课程(千锋教育),跟老师写程序,不是自创的代码!今天是学Python的第10天,学的内容是函数。开学了,时间不多,写得不多,见谅。目录1.函数入门2.函数使用说明1.定义函数2.函数组成3.函数命名4.函数参数5.函数易忘点6.函数的调用3.函数调用时的注意事项4.函数的参数(1......
  • 【JVM】—JVM垃圾回收详解
    JVM垃圾回收详解⭐⭐⭐⭐⭐⭐Github主页......
  • JVM的GC算法以及常见垃圾回收器
    针对简历技能:熟悉JVM的GC算法、常见垃圾回收器针对HotSpotVM的实现,它里面的GC其实准确分类只有两大种:部分收集(PartialGC):新生代收集(MinorGC/YoungGC):只对新生代进行垃圾收集;老年代收集(MajorGC/OldGC):只对老年代进行垃圾收集。混合收集(MixedGC):对整个新生代......
  • 图文深入理解java对象从创建到回收都经历了什么
    1.前言:每个java对象都是有生命周期的,就像一个人的生命一样,从孕育到出生到成长变老最后由归于自然。笔者认为,Java对象的整个生命周期可以分为两个大的阶段:即创建阶段和运行阶段(包含对象的回收和消亡)。本篇将会图文深入介绍java对象的整个生命过程。一般人平时看到java其实......
  • 【网络原理大花园】https 加密技术的深度解析,让你透彻理解, 建议收藏 ~ ~ ~
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......