Java虚拟机JVM知识点(已完结)

news2025/4/3 5:27:05

JVM内存模型

介绍下内存模型

根据JDK8的规范,我们的JVM内存模型可以拆分为:程序计数器、Java虚拟机栈、堆、元空间、本地方法栈,还有一部分叫直接内存,属于操作系统的本地内存,也是可以直接操作的。

详细解释一下

  • 程序计数器:可以看作是当前线程所执行的字节码的行号指示器,用于存储当前线程正在执行的Java方法的JVM指令地址。
  • Java虚拟机栈:每个线程都有一个独立的Java虚拟机栈,生命周期和线程相同。每个方法在执行时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等,可能抛出OOM和StackOverflowError异常。
  • 本地方法栈:与Java虚拟机栈类型,主要为虚拟机使用到的Native方法服务,在HotSpot虚拟机中和Java虚拟机栈合二为一。本地方法执行时也会创建栈帧,同样也可以抛出OOM和StackOverflowError异常。
  • 方法区(元空间):在JDK8以后的版本中,方法区被元空间取代,使用本地内存。用于存储已被虚拟机加载的类信息、常量、静态变量等数据。虽然方法区被描述为堆堆逻辑部分。方法区可以选择不进行垃圾回收。同样可以抛出OOM和StackOverflowError异常。
  • Java堆:在JVM最大的一个部分,被所有线程所共享,当虚拟机启动时,用于存放所有的对象实例。从垃圾回收的角度,分为新生代和老年代,新生代分为伊甸区(Eden)和幸存区(Survivor分为From Survivor和To Survivor),如果在堆中没有内存完成实例分配,并且堆也无法扩展时会OOM。
  • 运行时常量池:是方法的一部分,用于存放编译期间生成的各种字面量和符号引用,具有动态性。
  • 直接内存:不属于JVM运行时数据区的一部分,通过NIO引入,是一种堆外内存,可以显著提高i/o性能。

JVM内存模型中堆和栈的区别

  • 用途:栈主要用于存储局部变量、方法参数的调用、方法返回地址以及一些临时数据。每当一个方法被调用,就会创建一个栈帧,用于存储方法的信息,方法执行完毕,栈帧也会被移除。堆用于存储对象的实例,当你使用new去创建一个对象时,对象实例就会在上面分配空间。
  • 生命周期:栈中的数据具有确定的生命周期,当一个方法结束调用时,其对应的帧栈就会被移除,栈中存储的局部变量也就会消失。堆中的对象没有固定的生命周期,闲置对象会在垃圾回收机制下被回收。
  • 存取速度:栈的存取速度比堆快,因为栈遵循先进后出FIFO的原则,操作简单快速。堆的存取速度较慢,因为对象在对上分配和回收需要更多的时间,垃圾回收机制也会影响性能。
  • 存储空间:栈的空间相对较小,且较为固定,由操作系统管理。当栈溢出时,通常因为递归过深或者局部变量过大。堆的空间较大,动态扩展,由JVM管理,堆溢出通常由于创建了太多的大对象未及时收回。
  • 可见性:栈中的数据对线程是私有的,每个线程有自己的栈空间。堆中的数据对线程是共享的,所有线程都可以访问堆上的对象。

栈中存储的到底是指针还是对象

在JVM内存模型中,栈主要用于管理线程的局部变量和方法的上下文调用,而堆是粗处所有类的实例和数组。

当我们在讨论存储时,实际上栈中存储的是方法执行时的基本数据类型和对象的引用,这里注意是对象的引用,不是对象本体,指向堆中对象的实例。

堆分为哪几部分呢

  • 新生代:新生代分为Eden伊甸区和幸存区。在伊甸区中,大多数新创建的对象都会放在这里,Eden区相对较少,当Eden区满时,会触发一个Minor GC(轻GC)。在幸存区中,通常分为两个大小相等的部分,每次Minor GC时,存活下来的对象会被移动到其中的一个幸存区,以继续他们的生命周期。
  • 老年代:存放过一次或多次Minor GC仍存活的对象会被移动到老年代。老年代的生命周期较长,因此Full GC发生频率较低,但是执行时间比Minor GC长,老年代空间比新生代长。
  • 元空间:从Java8开始,永久代被元空间取代,用于存储类的元信息,如类的结构信息等。元空间不在堆红,而是使用了本地内存,解决了永久代OOM的问题。
  • 大对象区:在某些JVM实现中引入了大对象区,指需要大量连续的内存空间的对象,如大数组,这类对象直接放在老年代,避免年轻代的晋升而导致内存碎片化。

方法区的执行过程

  • 解析方法调用:JVM会根据方法的符号引用找到实际方法地址。
  • 栈帧创建:在调用一个方法前,JVM会在当前线程的Java虚拟机栈中为该方法分配一个新的栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口信息。
  • 执行方法:执行方法内的字节码命令,涉及的操作可能包括局部变量的读写等操作。
  • 返回处理:方法执行完毕后,可能会返回一个结果给调用者,并清理当前栈帧,恢复调用者的执行环境。

String保存在那里?

String是包存在字符串常量池中,不同于其他对象,他的值是不可变的,可以被多个引用共享。

引用类型有哪些?有什么区别

  • 强引用类型:是代码中普遍的赋值方式,比如A a = new A();这样的发过誓。强引用关联的对象,永远不会被垃圾回收器回收。
  • 软引用类型:可以用SoftReference来描述,指的是那些有用但是不是必须要的对象。系统在发生内存溢出前会针对这样的对象进行回收。
  • 弱引用:可以用WeakReference来描述,他的强度比软引用低,弱引用的对象下一次GC的时候一定会被回收,不管内存是否足够。
  • 虚引用:幻影引用,是最弱的引用关系,他必须和ReferenceQueue一起使用,当GC发生时,虚引用也会被回收。可以用虚引用来管理堆外内存。

弱引用了解吗?举例说明

Java中的弱引用是一种引用类型,他不会阻止一个对象被垃圾回收。

  • 缓存系统:弱引用常用来实现缓存,特别是当希望缓存项能够在内存压力下自动释放时。如果缓存的大小不受控制,可能会导致内存溢出。使用弱引用来维护缓存,可以让JVM在需要更多内存的时候自动清理这些对象。
  • 对象池:在对象池中,弱引用可以用来管理那些暂时不用的对象。当对象不再被强引用时,他可以被垃圾回收,释放内存。
  • 避免内存泄漏:当一个对象不应该被长期引用时,使用弱引用可以防止该对象被意外的保留,避免的潜在的内存泄漏。

内存泄漏和内存溢出的理解

内存泄露:内存泄露通常是在程序运行中不再使用的对象仍然被引用,从而无法被垃圾回收器回收,从而导致可用内存逐渐变少,虽然在Java中,垃圾回收机制会自动回收不再引用的对象,但是仍有对象不会被回收,最终导致程序内存不断增加。

导致内存泄漏的原因

  • 静态集合:使用静态的数据结构存储对象,且没有清理。
  • 事件监听:未取消对事件的监听,导致对象被持续引用
  • 线程:未停止的线程可能持有对象的引用,无法被回收

内存溢出:内存溢出指的是Java虚拟机在申请内存时,无法找到足够的内存,最终引发OOM。

内存溢出主要原因

  • 大量对象创建:程序中不断创建大量对象,超出JVM堆的限制。
  • 持久引用:大型数据结构长时间持有对象的引用,导致内存积累
  • 递归调用:深度递归导致栈溢出

JVM内存结构中有哪几种内存溢出的情况

  • 堆内存溢出:当出现OOM时,就是堆内存溢出了,原因是代码中可能存在大对象分配。或者发生了内存泄漏,导致多次GC之后,仍无法找到一个合适的空间存放当前对象。
  • 栈内存溢出:如果我们写一个程序不断的递归调用,而且没有退出条件,就回导致不断的进行压栈。类似于这种情况会JVM会抛出:SOF。如果JVM试图扩展栈空间失败,则直接报出OOM。
  • 元空间溢出:出现这个异常是系统的代码非常多或者引用了过多的第三方包或者通过动态代码加载类的操作,导致元空间内存被压满
  • 直接内存溢出:在使用ByteBuffer会使用到,很多JavaNIO的框架(Neety和Vert.x)被封装为其他的方法会抛出OOM。

类初始化和加载

创建对象的过程

  1. 类加载检查:虚拟机收到一条new指令时,首先将去检查这个指令的参数能否在常量池中定位到一个类的符号引用。并检查这个符号引用代表的类是否被加载、解析和初始化过。如果没有则必须先进行相应的类加载工程。
  2. 分配内存:在类加载检查过程后,接下来虚拟机将为新生代分配内存。对象所需的内存大小在类加载后方可确定,将对象所需要的空间从Java堆中划分出来。
  3. 初始化零值:内存分配完成后,虚拟机需要将分配到的内存空间初始化为0值,这一步保证了对象的实例字段在Java中可以不赋值就可以直接使用,程序能够能访问到这些字段的数据类型所对应的零值。
  4. 进行必要设置(对象头):初始化零值完成之后,虚拟机需要对对象进行必要的设置。也就是初始化对象头。
  5. 执行init方法:在上面工作完成后,在JVM看来,一个对象已经执行完毕了。但是在程序看来,才刚刚开始。需要根据程序设计者的思路来初始化对象。

对象生命周期

  • 创建:对象通过关键字new在堆内存中被初始化,构造函数被调用,对象内存空间被分配。
  • 使用:对象被引用并执行相应操作。
  • 销毁:当对象部呗引用时,通过垃圾回收机制自动回收对象所占用的内存空间。

类加载器都有哪些

  • 启动类加载器:这是最顶层的加载器,负责加载Java的核心库,是使用C++编写的,是JVM的一部分,启动类加载器无法被Java程序直接引用。
  • 扩展类加载器:他是Java语言实现的,继承自ClassLoader类,负责加载Java扩展目录下的jar包和类库,扩展类加载器由启动类加载器加载,并且父加载器就是启动类加载器。
  • 系统类加载器:这也是Java语言实现的,负责加载用户类路径上的指定类库,是我们平时编写Java默认使用的加载器。
  • 自定义类加载器:用户定制的类加载器。

这些类加载器之间的关系形成了双亲委派模型,核心思想是当一个类加载器收到类加载请求时,首先不去自己尝试加载这个类,而是把这个请求委派给副加载器去完成,每一层都是如此,因此所加载请求最终都应该传送到顶层加载器中。

双亲委派到作用

  • 保证类的唯一性:通过委托机制,保证每一个加载请求都会传递到启动类加载器,避免不同的加载器加载相同的类,保证了Java核心库的一致性
  • 保证安全性:防止不可信的类假冒核心类。因为都会被委托到顶层的启动类加载器。
  • 隔离和层次划分:双亲委派模型支持不同层次的类加载器服务于不用的类的加载请求。
  • 简化加载流程:通过委派,大部分类能够被正确的类加载器加载,减少了每个加载器需要处理类的数量,简化加载过程。

讲一下类加载的过程

  • 加载:通过类的全限定名获取到类的.class文件的二进制字节流,将二进制字节流所代表的静态存储结构转化为方法区运行时的数据结构,在内存中生成一个代表该类的Java.lang.Class对象,作为方法区这个类的各种入口。
  • 连接:
    • 验证:验证这个类的字节流内所包含的信息是否符合当前虚拟机要求。
    • 准备:将静态资源赋0值
    • 解析:将符号引用直接替换为直接引用
  • 初始化:初始化是整个类加载过程中的最后一个阶段,初始化阶段简单来说执行构造器方法们要注意这个构造器不是开发者写的,是编译器生成的。
  • 使用类或者对象
  • 卸载:当一个类的所有实例都被回收,也就是Java堆中不存在该类的任何实例,加载类的ClassLoader已经被回收。类对应的Java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射获取对象。

垃圾回收

什么是Java中的内存回收。如何触发垃圾回收

垃圾回收是一种自动管理内存的机制,他负责自动释放不再被程序引用的对象所占用的内存,这种机制减少了内存泄漏和内存管理错误的可能性。

  • 内存不足时释放:当JVM检测到内存不足时,无法为新的对象分配内存时,会自动触发垃圾回收。
  • 手动请求:虽然垃圾回收是自动的,开发者可以通过调用System.gc()或者其他方法进行垃圾回收。不过这只是一个建议,并不能保证立即执行。
  • JVM参数:启动Java应用可以通过调整JVM参数来进行垃圾回收行为。比如:-Xmx、-Xms。
  • 对象数量或者使用达到阈值:垃圾回收内部实现了一些策略,以监控对象的创建和使用。

判断垃圾的方法

在Java中判断对象是否为垃圾(即不被引用,可以被垃圾回收器回收),主要依据两种垃圾回收算法来实现:引用计数法和可达性算法。

引用计数法

  • 原理:为每个对象分配一个引用计数器,每当有一个地方引用它时,计数器加一,当引用失效时,计数器减1,当计数器为0,对象不再被任何变量引用,可以被回收。
  • 缺点:有循环引用的问题,当两个对象循环引用时,两个对象此时的引用计数都为1,谁也不放谁,就会导致对象无法被回收。

可达性分析算法

Java虚拟机主要采用这种算法来判断对象是否为垃圾。

原理:从一组称为GC Roots(垃圾收集根)的对象出发,向下追溯他们的引用对象,以及这些对象引用的其他对象,以此类推,如果一个对象的GC Roote没有任何引用连接,那么这个对象就被认为是垃圾对象,可以被回收。

垃圾回收算法

  • 标记清除法:标记清除法,分为标记+清除两个部分,首先通过可达性分析标记出所有需要回收的对象,然后再直接清除。标记清除法有两个缺点,第一个是效率比较低,标记和清除的效率都比较低,再就是收集零散空间的垃圾会产生大量磁盘碎片,可能会造成申请大内存时直接OOM的问题。
  • 复制算法:为了解决内存碎片的问题,出现了复制算法。复制算法的原理是将内存分为两框,每次申请内存时都使用其中一块,当内存不够时,将这一块内存中所有存活的复制到另一块上,然后再将这一块直接清空,但是也带来新的问题,当需要分配超大连续内存时会导致直接OOM。
  • 标记整理算法:标记使用可达性算法记录出要被回收的垃圾,但是先不清除,先将存活的对象移到另一端,然后再清理剩余部分。
  • 分代回收算法:分代回收是将内存划分为新生代和老年代。分配对象的依据是对象的生命周期,或者是经历过GC的次数。对象创建时一般是在新生代创建内存,当经历一定次数的GC后仍然存活会移动到老年代。

MinorGC(Young GC)和majorGC和Full GC的区别

YoungGC

  • 只针对年轻代进行回收,包括伊甸区和两个幸存区。
  • 当伊甸区空间不足时就会出发一次YoungGC,并将存活的对象移动到幸存区。
  • 通常发生的特别频繁,因为年轻代中对象的生命周期很短,回收效率高。

MajorGC

  • 针对老年代进行回收,但不一定只回收老年代
  • 当老年代空间不足时,或者系统检测到年轻代对象晋升过快,可能出发MajorGC

Full GC

对整个堆内存进行回收。

  • 直接调用System.gc()或Runtime.getRuntime().gc() 方法时,虽然不能保证立即执行,但JVM会尝试执行Full gc
  • Minor GC时,如果存活的对象无法全部放入老年代,或者老年代空间不足以容纳存活的对象,则会出发Full GC,对堆内存进行回收。
  • 当永久代或元空间空间不足时,出发FullGC

Full GC是最昂贵的操作,它需要停止所有工作线程,遍历整个堆内存来查找和回收不再使用的对象,因此尽量减少使用Full GC。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2326977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++进阶四】vector模拟实现

目录 1.构造函数 (1)无参构造 (2)带参构造函数 (3)用迭代器构造初始化函数 (4)拷贝构造函数 2.operator= 3.operator[] 4.size() 5.capacity() 6.push_back 7.reserve 8.迭代器(vector的原生指针) 9.resize 10.pop_back 11.insert 12.erase 13.memcpy…

VUE3+Mapbox-GL 实现鼠标绘制矩形功能的详细代码和讲解

以下是如何使用 Mapbox GL JS 实现鼠标绘制矩形功能的详细代码和讲解。Mapbox GL JS 是一个强大的 JavaScript 库,可以用来创建交互式地图。下面将通过监听鼠标事件并动态更新地图图层来实现这一功能。 实现步骤 初始化地图 在 HTML 文件中引入 Mapbox GL JS 库&…

《筋斗云的K8s容器化迁移》

点击下面图片带您领略全新的嵌入式学习路线 🔥爆款热榜 88万阅读 1.6万收藏 文章目录 **第一章:斗战胜佛的延迟焦虑****第二章:微服务化的紧箍咒****第三章:混沌中的流量劫持****第四章:量子筋斗的终极形态****终章&…

基于SpringBoot的“考研学习分享平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“考研学习分享平台”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统总体功能结构图 局部E-R图 系统首页界面 …

Web3.0隐私计算与云手机的结合

Web3.0隐私计算与云手机的结合 Web3.0隐私计算与云手机的结合,标志着从“数据垄断”向“数据自主”的范式转变。通过技术互补,两者能够构建更安全、高效且用户主导的数字生态。尽管面临技术整合和成本挑战,但随着区块链、AI和分布式存储的成…

Linux上位机开发实践(超越MPP去开发产品)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 对于芯片厂商来说,肯定希望客户的应用和自己的芯片绑定地越紧密越好。最好就是,他们自己成为客户的独家供应商。但是对于嵌…

SpringBean模块(二)bean初始化(2)和容器初始化顺序的比较--引入ApplicationContextInitializer

前面介绍了获取容器可以让spring bean实现ApplicationContextAware,实际也是初始化执行了setApplicationContext接口, 初始化接口还可以借助一些注解或者spring bean的初始化方法,那么他们的执行顺序是什么样的呢? 一、验证&…

【分享】内外网文件摆渡系统:让数据传输更安全更可靠

【分享】Ftrans内外网文件摆渡系统:让数据传输更安全更可靠! 随着大数据时代的到来,数据的重要性日渐得到重视,数据作为数字经济时代下的基础性资源和战略性资源,是决定国家经济发展水平和竞争力的核心驱动力。以行业…

2025年江苏省职业院校技能大赛 (高职组)大数据应用开发赛项任务书 (样题)

2025年江苏省职业院校技能大赛 (高职组)大数据应用开发赛项任务书 (样题) 背景描述:任务A:离线数据处理(35分)子任务一:数据抽取子任务三:指标计算 任务B&…

手机显示5GA图标的条件

最近有星友问在什么情况下才能显示5G-A?虽然这个我也不知道,但是我有几个运营商的5G终端白皮书,从上面就可以找到答案。 如上是几个运营商显示5G-A的条件,基本上考虑的都是3CC的情况,联通还有考虑200M CA 2CC的场景&am…

Spring Boot 实现文件秒传功能

前言 在开发Web应用时,文件上传是一个常见需求。然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余。此时可以使用文件秒传技术通过识别重复文件,实现瞬间完成上传的效果,大大提升了用户体验…

使用AOP技术实现Java通用接口验签工具

一、背景 在给第三方提供接口时,我们需要对接口进行验签。具体来说,当外部系统调用我们的接口时,请求中需要携带一个签名,我们接收到请求后,会解析数据并校验签名是否正确,以确保请求的合法性和安全性。 为了在不同项目中方便地使用这一功能,我们将签名校验规则封装成一…

aarch64-none-elf-gcc与aarch64-linux-gnu-gcc

1. 场景描述 在Ubuntu 24.04.1 LTS x86_64架构下交叉编译能跑在aarch64架构下裸机程序,遇到缺aarch64-none-elf-gcc的情况,做此记录。 2. aarch64-none-elf-gcc与aarch64-linux-gnu-gcc 运行环境 aarch64-none-elf-gcc 生成的代码是 裸机程序&#xf…

【清华大学】DeepSeek政务应用场景与解决方案

目录 一、政务数字化转型三阶段演进二、人工智能政务应用场景四大方向 三、技术方案核心技术 四、解决方案案例1. 公文写作2. 合同协议智能审查3. 行政执法4. 就业指导 五、风险及对策六、落地大四步法七、未来发展展望AI职业替代逻辑空间智能与具身智能人机共生 一、政务数字化…

4.2 单相机引导机器人放料-仅考虑角度变化

【案例说明】 本案例产品在托盘中,角度变化不大(<15度);抓取没有问题,只是放的穴位只能容许3度的角度偏差,因此需要测量产品的角度。 思路是:机器人抓料后、去固定拍照位拍照(找到与标准照片的角度偏差),机器人在放料的位置上多旋转这个角度偏差,把产品放进去。 …

论文阅读笔记:Denoising Diffusion Implicit Models (3)

0、快速访问 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08;1&#xff09; 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08;2&#xff09; 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08…

Git(八)如何在同一台电脑登录两个Git

目录 一、理解 SSH 密钥机制二、具体实现步骤1.删除GIT全局配置2.生成多个 SSH 密钥3.添加公钥到 Git 账户4.配置 SSH config 文件5.测试SSH key是否生效6.下载代码 三、Git仓库级别配置四、HTTPS方式的多账号管理 引言&#xff1a; 在日常开发中&#xff0c;我们经常会遇到需要…

如何改电脑网络ip地址:一步步指导

有时我们需要更改电脑的网络IP地址以满足特定的网络需求。本文将为您提供一份详细的步骤指南&#xff0c;帮助您轻松完成电脑网络IP地址的更改。以下是更改计算机IP地址的分步指南&#xff0c;适用于常见的操作系统&#xff1a; 一、更换内网ip Windows 系统&#xff08;Win10…

PyTorch 分布式训练(Distributed Data Parallel, DDP)简介

PyTorch 分布式训练&#xff08;Distributed Data Parallel, DDP&#xff09; 一、DDP 核心概念 torch.nn.parallel.DistributedDataParallel 1. DDP 是什么&#xff1f; Distributed Data Parallel (DDP) 是 PyTorch 提供的分布式训练接口&#xff0c;DistributedDataPara…

【Unity】记录TMPro使用过程踩的一些坑

1、打包到webgl无法输入中文&#xff0c;编辑器模式可以&#xff0c;但是webgl不行&#xff0c;试过网上的脚本&#xff0c;还是不行 解决方法&#xff1a;暂时没找到 2、针对字体asset是中文时&#xff0c;overflow的效果模式处理奇怪&#xff0c;它会出现除了overflow模式以…