首页 > 系统相关 >JVM面试(二)内存区域划分

JVM面试(二)内存区域划分

时间:2024-09-03 17:24:19浏览次数:7  
标签:Java 虚拟机 面试 线程 内存 JVM 方法 堆区

内存区划分

Java虚拟机在执行Java程序的过程中会把它锁管理的内存划分为若干个不同的数据区域。 这些区域有各自不同的用途,以及创建和销毁的时间。 有的区域随着虚拟机的进程一直存在,有的区域依赖用户线程的启动和结束而建立和销毁。

根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存,包含一下几个运行时的数据区域。如图:

在这里插入图片描述

一般我们面试的时候,都是笼统的说:堆、栈、以及方法区,JDK 8之后方法区变为“元空间”。
这个说法不错,下面我们详解一下。

程序计数器

程序计数器区域⼀块内存较小的区域,它⽤于存储线程的每个执行指令,每个线程都有自己的程序计数器,此区域不会有内存溢出的情况。
由于Java虚拟机的多线程是通过线程的轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器都只执行一个线程。
那么为了每次切换线程后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器, 所以这个程序计数器区域,是一个线程私有的内存。

虚拟机栈与本地线程栈

在很多情况下,我们都是把这两个合在一起说的。
两方面的原因,一个是《Java虚拟机规范》对本地方法栈使用的语言、使用方式等没有任何规定。 二是有些虚拟机确实把这两个合二为一,比如Hot-Spot虚拟机。

如果按照我这里的浅显理解的话,他们之间的区别可以这么说。
虚拟机栈的生命周期与线程相同,主要就是存储线程执行相关的局部变量信息。
本地方法栈也是如此,但是所执行的内容可能是虚拟机本地方法Native。

所以我们在面试的时候,可以只说虚拟机栈,甚至直说本地方法栈都可以。(在我面试数十次的经历中,确实没有遇到,挑这两个问区别的)

回到虚拟机栈,在每个方法被执行的时候,Java虚拟机都会在这个线程栈中创建一个“栈帧”,用于存储局部变量表,操作数栈,方法出口等等信息。每一个方法被调用,直到执行完毕,就对应着一个栈帧从入栈到出栈的过程。

因为我们线程调用方法是一层层递进的,所以这个栈帧也是一层层叠加。当调用深度超过虚拟机所允许的深度时,就会抛出StackOverflowError异常。

还有一个情况是,栈帧层层递进的时候,虚拟机栈也是在不断增大。
如果栈的内存不足,并且提前分配好不能扩展;或者是扩展的时候无法申请到足够的内存,就会发生OutOfMemoryError异常。

堆区

堆区是各个线程共享的区域。
这也是老生常谈的问题,主要存放JVM启动时创建的数组和对象实例,还有垃圾回收也主要在堆区发生,还有分代模型等等巴拉巴拉。
具体内容我们可以到分析垃圾回收的时候详细说下。
需要注意的是,堆区也是可以被固定大小的,当内存不足无法扩展时,也会抛出OutOfMemoryError异常。

方法区

与堆区一样,也是各个线程共享的区域。
主要存储那些常亮,静态变量,代码缓存等数据。虽然《Java虚拟机规范》中把方法区描述为一个堆区的逻辑部分,但是名字却为“Non-Heap” 非堆,这就是要与堆区做区分。

这里不得不提一下“永久代” 这个概念,以前很多时候都是把永久代与方法区混为一谈。
这是因为HotSpot虚拟机的设计团队把垃圾收集器的分代设计扩展到了方法区,把方法区称为永久代来管理垃圾回收机制。

但是后来又把永久代的概念放到了本地内存中,一直到JDK8 之后,完全放弃了永久代的概念,改为在本地内存新实现的“元空间”来代替

粗略来说,就是最早时候方法区=永久代,后来统一并入本地内存的“元空间”中。

运行时常量池

也是方法区的一部分,主要 存储Class文件中编译期生成的各种字面量与符号引用

字面量是源代码中的固定值的表示法,即通过字面我们就能知道其值的含义。字面量包括整数、浮点数和字符串字面量;

符号引用包括类符号引用、字段符号引用、方法符号引用和接口方法符号引用。符号引用就是⼀个字符串,只要我们在代码中引用了⼀个非字面量的东西,不管它是变量还是常量,它都只是由⼀个字符串定义的符号,这个字符串存在常量池里,类加载的时候第一次加载到这个符号时,就会将这个符号引用(字符串)解析成直接引用(指针)。

标签:Java,虚拟机,面试,线程,内存,JVM,方法,堆区
From: https://blog.csdn.net/weixin_41011482/article/details/141820164

相关文章

  • Java内存泄露诊断与预防策略
    Java内存泄露诊断与预防策略大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java应用开发中,内存泄露是一个常见且棘手的问题。它不仅会导致应用性能下降,还可能引起应用崩溃。因此,了解如何诊断和预防内存泄露至关重要。内存泄露的定义内存泄露发生......
  • 【c】结构体内存对齐的规则
    规则一、成员变量内存相对起始位置为数据类型所占内存的整数倍(例如:int类型数据相对起始位置必须是结构体中4字节的整数倍),若不足则需要对齐不足部分的内存(内存补充给前一个变量)。二、结构体所占总内存为其成员变量中所占空间最大数据类型的整数倍。三、结构体中每个成员相对......
  • 单片机内存区域划分
    目录一、C语言内存分区1、栈区2、堆区3、全局区(静态区)4、常量区5、代码区6、总结二、单片机存储分配1、存储器1.1RAM1.2ROM1.3FlashMemory1.4不同数据的存放位置2、程序占用内存大小一、C语言内存分区C语言在内存中一共分为如下几个区域,分别是:下面分别......
  • 深入理解Java内存模型:对并发编程的启示
    深入理解Java内存模型:对并发编程的启示大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java并发编程中,Java内存模型(JMM)是一个至关重要的概念。它定义了Java程序中各种变量的访问规则,以及这些变量如何与计算机内存交互。正确理解JMM对于编写高效、可......
  • 【Go 实践学习】内存泄漏情景及pprof工具使用(上半篇)
    目录什么是内存泄漏?两类内存泄漏暂时性内存泄漏永久性内存泄漏常见的内存泄漏及解决办法浅拷贝共享底层资源,导致无关内存无法释放子切片导致的内存泄漏子字符串导致的内存泄漏子切片未重置指针索引挂起的goroutines导致的内存泄漏死循环导致的内存泄漏阻塞的通道读......
  • Java面试——SpringBoot篇
    前置知识ApplicationContextInitializerApplicationContextInitializer是Spring框架中的一个扩展接口,用于在应用程序上下文(ApplicationContext)创建之前对其进行自定义初始化。通过实现该接口,您可以在应用程序上下文启动之前执行一些额外的配置或准备工作。应用场景动态加载......
  • 《ARM Cortex-R 学习指南》-【第九章】-内存保护单元
    第九章内存保护单元许多实时系统在多任务操作系统(OS)下运行。操作系统提供了一种机制,以确保当前执行的任务不会干扰其他任务的操作。系统资源、其他任务的代码和数据都受到保护。保护系统通常依赖于硬件和软件的结合。在没有硬件保护支持的系统中,每个任务必须与其他任务协......
  • 大模型微调中的内存效率问题及解决方案
    人工智能咨询培训老师叶梓转载标明出处大模型(LLMs)在大规模训练中的内存消耗问题日益凸显,传统的参数高效微调技术,如低秩适应(LoRA),虽然在一定程度上缓解了这一问题,但其性能在很多大规模微调场景下仍无法与全参数训练相媲美。为了解决上述问题,香港科技大学以及伊利诺伊大学香槟......
  • 规控面试复盘
    目录前言一、京东方1、CPP和C的区别是什么?2、讲一下的ROS的话题通信二、Momenta(泊车部门实习面试)1、MPC的预测时间步是多少?2、MPC的代价函数考虑的是什么?三、九识1、智能指针有哪些优缺点?优点:缺点:2、Protobuf的数据传输效率为什么更高?3、Protobuf和ros原生的msg......
  • 我的渗透测试路,如何入门网络安全最高效?附面试经验
    前言这篇先回顾一下我大学时候的渗透经历,再说一下哪几个方面对于渗透测试入门或者发展来说是最重要、最高效的。(知乎的文章编辑功能太辣鸡了,有好多格式问题,建议到我的公众号看噢,公众号二维码位于文章底部)大学的渗透路在高考结束后,我知道了自己的成绩,仅超过一本线几分可......