当前位置: 首页 > news >正文

【Java虚拟机】JVM内存模型

JVM的内存模型

JVM的运行时内存主要分为Java虚拟机栈,堆,本地方法栈,程序计数器,元空间五个部分,还有一部分是直接内存,是操作系统的本地内存,也是可以直接操作的。

Java虚拟机栈

每个线程都有一个独立的虚拟机栈,并且在方法执行前都会在栈中创建一个栈帧,用来存储该方法的一些信息。

Java堆

堆是JVM中最大的一块区域,它是所有线程共享的,用来存储对对象的实例。每当遇到一个new关键字时,都会在堆中为其分配一块内存

本地方法栈

与虚拟机栈类似,本地方法栈是服务于本地方法的,当方法执行时也会创建一个栈帧。

程序计数器

程序计数器可以看作是Java程序运行字节码文件的行号指示器。它用来存储正在执行的Java方法的JVM指令地址。当执行本地方法时,它的值为null。

元空间

Java8以后,方法区被元空间所取代,它用来存放已将被虚拟机加载的类信息,常量,静态变量等信息。虽然它被称为堆的逻辑部分,但是还有“非堆”的别名,可以不实现垃圾回收

运行时常量池

运行时常量池是方法区的一部分,用于存放编译时产生的各种字面量和符号

直接内存

通过NIO类引入,极大提高了IO性能。直接内存的使用受到本机总内存的限制。

JVM内存模型里堆和栈有什么区别

  • 用途不同:每当方法执行时都会在栈中创建一个栈帧,用来存放该方法的信息。而堆是用来存放实例化对象的。每当使用new关键字创建一个新对象时,都会在堆中为其分配一片内存
  • 生命周期不同:栈中的栈帧有明确的生命周期,在方法被调用时被创建,方法运行结束后被清除。而堆中没有明确的生命周期,当垃圾回收器监测到该对象不再被引用时,会将该对象进行清除
  • 空间不同:栈的空间相对较小,通常是不可变的。而堆的空间较大,而且是可扩展的
  • 存取速度不同:栈采用的是先进后出的数据结构,操作简单,存取速度较快。而堆的存取速度较慢,并且垃圾回收也需要消耗一定的时间
  • 可见性:栈是独立的,各个线程间是不可见的。而堆是被所有线程所共享的。

栈中存的是指针还是对象

存的是对象的引用

堆分为哪几部分

新生代

新生代又可以划分为伊甸区和幸存者区,幸存者区又可以划分为两个大小相等的区域,s0,s1。当一个新的对象被创建时通常首先会分配到伊甸区,当伊甸区满时会触发一次垃圾回收,在每次垃圾回收后都会将存活的对象移动到s0或s1。二者充当对象的中转站。帮助区分长期存活和短期存活的对象。

老年代

当经过多次垃圾回收后仍然存活的对象会被移动到老年代,这里的full GC频次较低,但是时间比较长。老年代的空间通常比新生代要大,用来存放更多长期存活的对象。

元空间

用来存放已将加载的类信息,常量,静态变量等信息。它不在堆内存中,而是在本地内存。解决了永久代的内存泄漏问题

大对象区

有些JVM的实现还有大对象区,用来专门存放放大对象

如果有一个大对象,一般存放在哪里

一般直接存放在老年代中,原因有两点

  • 第一:新生代空间较小,如果直接存放大对象会导致内存不足,频繁出发垃圾回收,而垃圾回收涉及到对象的复制和转移,造成大量消耗。放入老年代可以减少新生代的压力。
  • 第二:如果直接将大对象放入新生代,频繁将大对象进行分配和清理,会产生大量内存碎片。导致下次为大对象分配空间时找不到连续的大空间,造成内存溢出。而老年代空间较大,能够减少内存碎片的产生。

程序计数器为什么是私有的

Java程序允许多个线程同时运行。当线程1和线程2同时运行时,CPU就会为其分配时间片,当执行完线程1的时间片后代码还没有执行完毕,会先去执行线程2 的时间片。执行完毕后再回到线程一执行剩余代码。程序计数器就起到记录程序执行字节码指令地址的作用。因此是私有的

方法区中方法的执行过程

  • 方法解析调用:首先JVM会根据方法的符号引用找到方法的实际地址
  • 栈帧创建:执行方法前先在栈中创建栈帧用来存储该方法的相关信息
  • 执行方法:执行方法内的字节码指令
  • 处理返回结果:方法执行完毕后,可能会将执行结果返回给调用者。清除栈帧,回复调用者的执行环境

String保存在哪里

String保存在字符串常量池中,该对象是不可变的,被其他引用所共享

String s=new String(“abc”)涉及到哪些内存区域

首先我们看到new关键词,我们可以知道该对象是在堆内存中创建的。然后abc是被fianl所修饰的,我们会先去字符串常量池中去查询是否存在该字符串,如果存在直接返回引用,如果不存在会先在常量池中创建该字符串,并返回引用。因此分两种情况:
第一种情况:字符串常量池中存在,那么只涉及到一个对象的创建。
第二种情况:符串常量池中不存在,那么涉及到两个对象的创建。

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

  • 强引用:指代码中普遍存在的赋值方式,这种引用永远不会被垃圾回收
  • 软引用:指需要带不是必须的那些对象,当系统内存溢出前会将其进行垃圾回收
  • 弱引用:比软引用还要低一点,当下一次垃圾回收时,一定会被回收掉
  • 虚引用:最弱的引用,也被称为幻影引用。需要配合refenence queue使用。

弱引用可以用在哪里

弱引用通常用来创建非强制性对象引用,这些对象会在内存不足时自动进行垃圾回收。
使用场景:

  • 实现缓存:通过弱引用实现缓存可以在JVM需要更多内存时自动清理掉这些缓存对象
  • 对象池:使用弱引用管理这些不被使用的对象时,他们就可以被垃圾回收,释放内存
  • 避免内存泄漏:当一个对象长期不被使用时,可以使用弱引用防止该对象长期存在,导致内存泄漏。
http://www.dtcms.com/a/328980.html

相关文章:

  • OpenCV常见问题汇总
  • XML头部声明发送者信息的实现方法
  • k8s基本概念
  • vue3:customRef 自定义ref
  • 深度学习模型实现高效公平调度-MU-MIMO场景
  • 面试实战 问题二十九 Java 值传递与引用传递的区别详解
  • 解决Vscode每次连接ssh登入需要输入密码问题(免密登入)
  • NLP自然语言处理: FastText工具与迁移学习基础详解
  • Maven配置Docker插件推送至远程私有仓库
  • 【论文笔记】DOC: Improving Long Story Coherence With Detailed Outline Control
  • Linux应用软件编程---UI技术(frambuffer、内存映射、函数封装、打印各类图形)
  • 数据结构初阶(12)排序算法—插入排序(插入、希尔)(动图演示)
  • 【Datawhale AI 夏令营】金融文档分析检索增强生成系统的架构演变与方法论进展
  • CAN仲裁机制的原理
  • Android中获取状态栏高度
  • 用好Spring AI向量存储,全面释放AI潜能:打造高效RAG应用的加速引擎
  • Jetson NX Python环境搭建:使用APT轻松安装NumPy, scikit-learn, OpenCV
  • 【OSPP 开源之夏】Good First issue 第一步—— openEuler Embedded 计划
  • 机器学习⑤【线性回归(Linear Regression】
  • 记录RK3588的docker中启动rviz2报错
  • C++11新特性详解:从列表初始化到线程库
  • Linux系统编程Day13 -- 程序地址空间(进阶)
  • uniapp组件的开关选择器可以这个携带多参数
  • CVPR2025敲门砖丨机器人结合多模态+时空Transformer直冲高分,让你的论文不再灌水
  • docker network 与host的区别
  • Uni-app + Vue3+editor富文本编辑器完整实现指南
  • 学习STM32 脉冲计数实验
  • MySQL相关概念和易错知识点(6)(视图、用户管理)
  • Java 大视界 -- 基于 Java 的大数据可视化在能源互联网全景展示与能源调度决策支持中的应用
  • 深度学习与遥感入门(七)|CNN vs CNN+形态学属性(MP):特征工程到底值不值?