java面试题-JVM内存结构

news2024/11/27 10:25:58

整体结构:

1.说说JVM内存整体的结构?线程私有还是共享的?

JVM(Java Virtual Machine)内存可以分为以下几个部分:

  1. 程序计数器(Program Counter Register):是线程私有的,用于记录当前线程执行的字节码指令地址。

  1. Java虚拟机栈(JVM Stack):也是线程私有的,用于存储Java方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息。

  1. 本地方法栈(Native Method Stack):与Java虚拟机栈类似,也是线程私有的,用于存储本地方法执行时的局部变量表、操作数栈等信息。

  1. Java堆(Java Heap):是所有线程共享的内存区域,用于存储Java对象实例和数组等数据。Java堆又可分为新生代和老年代两部分,其中新生代又可分为Eden空间、Survivor空间1和Survivor空间2。

  1. 方法区(Method Area):也是所有线程共享的内存区域,用于存储已加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  1. 运行时常量池(Runtime Constant Pool):是方法区的一部分,用于存储编译期生成的各种字面量和符号引用,也是所有线程共享的。

  1. 直接内存(Direct Memory):不是JVM运行时数据区的一部分,但是JVM可以通过DirectByteBuffer类来操作直接内存。直接内存不受Java堆大小限制,可以使用本地系统内存。

总体来说,除了程序计数器、Java虚拟机栈和本地方法栈是线程私有的以外,其他内存区域都是所有线程共享的。

2.什么是程序计数器?

程序计数器(Program Counter Register)是JVM内存结构中的一部分,是线程私有的内存区域。它是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。当线程执行一个方法时,程序计数器记录的是正在执行的字节码的地址,当线程被切换回来时,它能够恢复到正确的执行位置。

在Java虚拟机中,每个线程都有自己的程序计数器,线程私有,所以它不会发生线程安全问题。当一个线程被创建时,它的程序计数器被初始化为0。在线程执行Java方法的时候,程序计数器会记录当前执行到哪个字节码指令。

程序计数器是一个非常小的内存区域,它是线程私有的,因此对于内存的使用并不是非常显著。但是,程序计数器在JVM的线程切换、异常处理、线程恢复等方面起着非常重要的作用。因此,程序计数器是JVM运行的必要组成部分,它的作用不容忽视。

3.什么是虚拟机栈

虚拟机栈(Java Virtual Machine Stack)是JVM内存结构中的一部分,是线程私有的内存区域,用于存储Java方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息。

当一个线程开始执行一个方法时,JVM会为该方法创建一个栈帧(Stack Frame),并把栈帧压入该线程的虚拟机栈中。一个栈帧包含了一个方法的局部变量表、操作数栈、常量池指针等信息。

Java虚拟机栈的大小是在JVM启动时就可以预设的,每个线程的虚拟机栈大小可以通过JVM启动参数进行配置。如果一个线程的虚拟机栈空间不足以支持当前方法的执行,那么就会抛出StackOverflowError异常;如果JVM不能再为新的栈帧分配内存空间,就会抛出OutOfMemoryError异常。

虚拟机栈是线程私有的内存区域,因此,不同的线程有自己的虚拟机栈。这个特性保证了线程之间的内存隔离,一个线程的虚拟机栈不能被其他线程访问。虚拟机栈的线程私有性使得多线程之间的数据共享和通信需要通过一些协调机制来实现。虚拟机栈的线程私有性也意味着它的内存分配和回收操作是线程独立的,不会发生线程安全问题。

4.Java虚拟机栈如何进行方法计算的?

Java虚拟机栈是线程私有的内存区域,用于存储Java方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息。当一个线程开始执行一个方法时,JVM会为该方法创建一个栈帧(Stack Frame),并把栈帧压入该线程的虚拟机栈中。一个栈帧包含了一个方法的局部变量表、操作数栈、常量池指针等信息。

当一个方法被调用时,JVM会将该方法的栈帧压入调用者线程的虚拟机栈中。执行该方法时,JVM会在该方法的栈帧中创建一个局部变量表,用于存储该方法的参数以及该方法中定义的局部变量。JVM还会在该栈帧中创建一个操作数栈,用于存储该方法中运算的操作数和中间结果。JVM通过操作数栈来进行方法的计算和运算。当方法返回时,JVM会弹出该方法的栈帧,将栈帧中的返回值传递给调用该方法的方法。

Java虚拟机栈通过栈帧来管理方法的调用和返回。在方法调用时,JVM会为该方法创建一个新的栈帧并压入调用者线程的虚拟机栈中;在方法返回时,JVM会弹出该方法的栈帧并返回结果。栈帧的创建和销毁是Java虚拟机栈的核心操作,因为它们涉及到方法的调用和返回,是程序运行的重要环节。

5.什么是本地方法栈

本地方法栈(Native Method Stack)是Java虚拟机栈的一部分,也是线程私有的内存区域,用于执行Native方法的。Native方法是指使用本地语言(如C、C++)编写的方法,可以被Java程序调用。与Java方法不同,Native方法的实现不在Java虚拟机中,而是在本地的操作系统和硬件平台上。

Java虚拟机通过本地方法栈来执行Native方法。当Java程序调用Native方法时,JVM会在本地方法栈中创建一个新的栈帧,并将Native方法的参数和返回值放在该栈帧中。Native方法的计算和运算都是在本地方法栈中进行的。当Native方法执行完毕时,JVM会将该方法的结果返回给Java程序,并弹出该方法的栈帧。

本地方法栈与虚拟机栈的功能类似,都是用于管理方法的调用和返回。但是,它们之间有一个重要的区别,即本地方法栈用于执行Native方法,而虚拟机栈用于执行Java方法。本地方法栈的大小也可以通过JVM启动参数进行配置。如果本地方法栈空间不足以支持当前Native方法的执行,就会抛出StackOverflowError异常;如果JVM不能再为新的栈帧分配内存空间,就会抛出OutOfMemoryError异常。

本地方法栈的线程私有性保证了不同线程之间的内存隔离,一个线程的本地方法栈不能被其他线程访问。本地方法栈的线程私有性还保证了它的内存分配和回收操作是线程独立的,不会发生线程安全问题。

6.什么是方法区

方法区(Method Area)是Java虚拟机中的一块内存区域,用于存储已经被加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据。方法区是线程共享的内存区域,也是Java虚拟机中的永久代(Permanent Generation)。

方法区存储的是类级别的数据,与Java虚拟机栈和本地方法栈不同,它不是用于存储方法的局部变量和操作数栈等线程私有的数据。方法区的内存结构包含了运行时常量池、静态变量、类信息、即时编译器编译后的代码等内容。

运行时常量池是方法区的一部分,用于存储类和接口中的常量池信息。常量池中存储了常量、符号引用、字面量等数据,是Java程序中一些重要的静态数据结构。静态变量是指被static修饰的类变量,它们被存储在方法区中,它们的生命周期与类的生命周期一样长。

方法区还存储了类和接口的相关信息,包括类的访问修饰符、父类和接口信息、字段和方法信息等。这些信息在类加载的过程中被加载到方法区中,一旦被加载,就会一直存在于方法区中,直到虚拟机退出或被垃圾回收器回收。

另外,方法区还存储了即时编译器编译后的代码,即编译器优化后的本地代码。这些代码是存储在方法区中的,当某个方法被多次调用时,虚拟机会将该方法编译成本地代码,并存储在方法区中,以提高程序的执行效率。

方法区的大小可以通过JVM启动参数进行配置,如果方法区的空间不足以支持类的加载、常量池和代码的存储等操作,就会抛出OutOfMemoryError异常。方法区的线程共享性保证了所有线程都可以访问相同的类信息和静态变量,从而实现了内存的共享。

7.永久代和元空间内存使用上的差异?

永久代(Permanent Generation)和元空间(Metaspace)都是Java虚拟机中用于存储类元信息的内存区域。然而,它们在内存使用上有以下几点差异:

  1. 永久代是Java虚拟机规范中的一部分,而元空间是Java 8 引入的新特性,用于代替永久代。因此,永久代只在Java虚拟机中存在,而元空间则是Java虚拟机的一部分,可以使用操作系统的内存。

  1. 永久代的内存空间是固定的,在启动JVM时就已经分配了固定大小的内存,而元空间使用的是堆外内存,它的大小可以随着应用程序的需要进行动态调整。

  1. 永久代使用的内存是由JVM的堆内存分配的,而元空间使用的内存是由操作系统分配的。

  1. 永久代在Java虚拟机内存中的位置是在堆内存的末尾,而元空间位于堆外内存中。

  1. 永久代存储了类的元信息和静态变量等,而元空间存储了类的元信息和方法区信息,包括类名、类的父类、接口、字段、方法等。在元空间中,字符串常量池被存储在堆内存中。

  1. 永久代有可能会出现内存溢出的情况,例如常量池中存储的数据过多,导致永久代空间不足。而元空间不存在永久代的内存溢出问题,但如果元空间使用过度,会导致堆外内存溢出的问题。

总的来说,元空间比永久代更加灵活和可靠,可以根据应用程序的需要进行动态调整,避免了永久代的内存溢出问题。但是,由于元空间使用的是堆外内存,可能会增加操作系统的内存负担,需要注意内存使用的平衡和性能的优化。

8.堆区内存是怎么细分的?

Java虚拟机的堆区是Java应用程序中最大的内存区域,用于存储对象实例和数组等数据。堆区内存的细分主要有三个方面:新生代、老年代和永久代(在JDK8之前)/元空间(在JDK8及以后)。

  1. 新生代(Young Generation):年轻代是Java堆中的一部分,用于存储新创建的对象。年轻代被分为三个部分:一个Eden区和两个Survivor区(From和To),通常比例为Eden : Survivor = 8 : 1。新创建的对象首先会被分配到Eden区,当Eden区内存满时,就会触发一次Minor GC(年轻代垃圾回收),将Eden区和Survivor区中的存活对象复制到另一个Survivor区中,并清空Eden区和原Survivor区的内存。

  1. 老年代(Old Generation):老年代是Java堆中的一部分,用于存储存活时间较长的对象。在经过多次Minor GC后,仍然存活的对象就会被转移到老年代。当老年代内存满时,就会触发一次Major GC(老年代垃圾回收),清理老年代中的无用对象。老年代中的对象的生命周期比年轻代中的对象要长,垃圾回收的频率也比较低。

  1. 永久代(Perm Generation)/元空间(Metaspace):永久代或元空间是Java堆中的一部分,用于存储Java类的元数据,包括类名、方法名、常量池、字段描述等。永久代是在Java 7及之前的版本中使用的内存区域,而元空间是Java 8及之后的版本中使用的内存区域。永久代和元空间都是用来存储静态内容,与Java应用程序的堆内存无关。

堆内存的细分使得Java虚拟机可以更好地管理对象的内存使用,避免内存溢出等问题。

9.JVM中对象在堆中的生命周期?

在JVM中,对象在堆中的生命周期可以被描述为以下几个阶段:

  1. 创建对象:当使用new关键字创建一个新的对象时,JVM会在堆中分配一块内存来存储该对象。

  1. 使用对象:对象被创建后,程序可以对其进行操作,例如设置对象的属性值、调用对象的方法等。

  1. 对象不再被引用:当一个对象不再被任何引用变量所引用时,即没有任何方式可以访问到该对象时,JVM会将该对象标记为垃圾对象(Garbage Object)。

  1. 垃圾回收:当JVM需要更多的堆空间来分配新的对象时,会触发垃圾回收机制(Garbage Collection),该机制会扫描堆内存中所有的对象,并回收那些不再被引用的对象的内存空间。

  1. 对象被销毁:在垃圾回收机制释放了该对象的内存空间后,该对象就被销毁了,它所占用的内存空间也被回收。

需要注意的是,JVM中的垃圾回收机制是自动进行的,程序员无法直接控制。但是程序员可以通过优化代码,避免内存泄漏等问题,从而使得垃圾回收机制的效率更高,提高程序的性能和稳定性。

10.JVM中对象的分配过程?

在JVM中,对象的分配过程通常包括以下步骤:

  1. 检查堆空间是否有足够的内存来分配新的对象。如果没有足够的内存,则会触发垃圾回收机制来释放一些不再被引用的对象所占用的内存空间。

  1. 为对象分配内存。在JVM中,堆内存的分配通常是按照指针碰撞(Bump the Pointer)或空闲列表(Free List)的方式进行的。指针碰撞方式将内存分为已经分配的内存和未分配的内存两部分,用一个指针(指向下一个未分配的内存地址)将这两部分隔开;空闲列表方式将内存分为已经分配的内存和未分配的内存两部分,已经分配的内存被链表所连接,未分配的内存则是一个个独立的块。在分配内存时,JVM会在未分配的内存中找到一块足够大的内存块,并将其标记为已分配状态。

  1. 对象初始化。在为对象分配内存后,JVM会将分配到的内存空间清零,然后进行对象初始化,包括设置对象头信息、设置对象的默认值等。

  1. 返回对象引用。对象分配并初始化完成后,JVM会返回一个指向该对象的引用,这个引用可以用来访问对象的成员变量和方法等。

11.什么是 TLAB (Thread Local Allocation Buffer)?

TLAB(Thread Local Allocation Buffer)是为了优化Java虚拟机中的对象分配而引入的一种技术,它的存在主要是为了提高多线程程序中的对象分配性能。

在默认情况下,Java虚拟机中的对象分配是通过堆内存分配完成的。由于堆内存是所有线程共享的,多个线程可能会竞争同一块内存区域进行对象分配,从而导致性能下降。而使用TLAB技术后,每个线程都有自己的内存缓冲区,可以避免多个线程之间的竞争,提高对象分配的性能。

TLAB 分配过程

TLAB技术的优点包括:

1.减少了线程之间的竞争。每个线程都有自己的TLAB缓冲区,因此不同线程之间不会发生竞争,避免了锁竞争等问题,提高了对象分配的性能。

2.避免了内存碎片问题。由于每个线程都有自己的TLAB缓冲区,因此可以避免内存碎片问题,提高了内存的利用率。

3.提高了GC的效率。由于对象分配的缓冲区是线程私有的,因此可以使GC更加高效,减少了GC的暂停时间。

需要注意的是,使用TLAB技术也会带来一些额外的开销,例如每个线程都需要维护自己的缓冲区、缓冲区大小的调整等等。因此,在某些情况下,禁用TLAB技术可能会更好地适应特定的应用场景。

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

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

相关文章

JUC并发编程(二)

一、过时方法 一些不推荐使用的方法已经过时,容易破坏同步代码块,使对象的锁得不到释放,进而造成线程死锁 二、守护线程 默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程…

spring中BeanFactory 和ApplicationContext

在学习spring的高阶内容时,我们有必要先回顾一下spring回顾spring1.什么是springspring是轻量级的,指核心jar包时很小的;非侵入式的一站式框架(数据持久层,web层,核心aop),为了简化企业级开发。核心是IOC&a…

Python自动化测试实战篇(6)用PO分层模式及思想,优化unittest+ddt+yaml+request登录接口自动化测试

这些是之前的文章,里面有一些基础的知识点在前面由于前面已经有写过,所以这一篇就不再详细对之前的内容进行描述 Python自动化测试实战篇(1)读取xlsx中账户密码,unittest框架实现通过requests接口post登录网站请求&…

计算及网络第一章

计算机网络-第一章 概述 文章目录计算机网络-第一章 概述计算机网络在信息时代中的作用互联网概述网络的网络互联网的组成网络的边缘部分互联网的核心部分电路交换的主要特点分组交换的主要特点计算机网络的类别几种不同类别的计算机网络计算及网络的性能计算机网络的性能指标计…

面向对象之-接口鉴权

1 需求 1.1 需求背景 为了保证接口调用的安全性,我们希望设计实现一个接口调用鉴权功能,只有经过认证之后的系统才能调用我们的接口,没有认证过的系统调用我们的接口会被拒绝。 2 需求分析 2.1 基础分析 对于如何做鉴权这样一个问题&…

配置 Haproxy 负载均衡群集

配置 haproxy 负载均衡群集 🏆荣誉认证:51CTO博客专家博主、TOP红人、明日之星;阿里云开发者社区专家博主、技术博主、星级博主。 💻微信公众号:微笑的段嘉许 📌本文由微笑的段嘉许原创! &#…

Android 基础知识4-3.3 Button(按钮)与ImageButton(图像按钮)详解

一、引言 今天给大家介绍的Android基本控件中的两个按钮控件,Button普通按钮和ImageButton图像按钮; 其实ImageButton和Button的用法基本类似,至于与图片相关的则和后面ImageView相同,所以本节 只对Button进行讲解,另外…

MySQL进阶之锁

锁是计算机中协调多个进程或线程并发访问资源的一种机制。在数据库中,除了传统的计算资源竞争之外,数据也是一种提供给许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决堆的一个问题,锁冲突也是影响数据…

Neo4j列表函数

使用列表 标量列表函数 size() 函数返回列表中的元素的数量 MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WITH p, collect (m.title) AS MovieTitles WITH p, MovieTitles, size(MovieTitles) AS NumMovies WHERE NumMovies > 20 RETURN p.name AS Actor, NumMovies, Movie…

浙大PTA拼题A读者验证码刷题页面、PTA免费刷题页面(不需要读者验证码)

有一个B站号李桥桉,很多年前讲过PTA里的一些题目的解法。近两年有好多同学反馈,需要读者码才能进行答题,不然只能免费注册、看题、编写代码,就是不能提交代码(大受震撼)。 咱就是说,会不会是同学们找错页面了&#xff…

【数据库】第十二章 数据库管理

第12章 数据库管理 数据库的物理存储 关于内存、外存、磁盘、硬盘、软盘、光盘的区别_Allenzyg的博客-CSDN博客_磁盘和硬盘的区别 数据库记录在磁盘上的存储 定长,变长跨块,非跨快 文件的组织方方法: 无序记录文件(堆文件heap或pile file…

eddsa 算法

信息安全课程设计:eddsa 算法 一、项目要求 使用 C 语言开发;可以实现公私钥生成、签名、认证;只需要手动输入明文,代码会自动生成公私钥、签名、认证;记录公私钥生成、签名、认证的时间;在 VS 上运行&am…

React useCallback如何使其性能最大化?

前言 React中最让人畅谈的就是其带来的灵活性,可以说写起来非常的舒服。但是也就是它的灵活性太强,往往让我们忽略了很多细节的地方,而就是这些细节的东西能进行优化,减小我们的性能开销。可以说刚学React和工作几年后写React的代…

JVM内存结构之堆(重要)

1、概述每个JVM进程有且只有一个堆,进程内的所有线程共享这块区域,堆区在JVM启动的时候即被创建,其空间大小也就确定了,是JVM内存结构中最大的一块区域。由于线程共享,堆也就成了JVM内存管理的核心区域。《Java虚拟机规…

热爱所有热爱

想成为这样的一个人,在工作中是一名充满极客精神的Programmer,处理遇到的问题能够游刃有余,能够做出优雅的设计,写出一手优秀的代码,还有着充分的学习能力和业务能力,做一名职场中的佼佼者。 在工作之余还能…

15、条件概率、全概率公式、贝叶斯公式、马尔科夫链

条件概率定义:设A、B是两个事件,且,P(A) > 0 则称 为事件A发生的条件下事件B的条件概率对这个式子进行变形,即可得到概率的乘法公式:P(A) > 0 时,则P(B) > 0 时,则乍一看,…

数字化转型导师坚鹏:BLM农商行数字化转型实战解决方案及案例

BLM农商行数字化转型实战解决方案及案例研究 ——以BLM模型为核心,践行知行合一思想,实现知行果合一 课程背景: 很多农商行存在以下问题: 不知道如何开展数字化转型工作? 不清楚农商行数字化转型方法论? …

Python—单分支结构

&#xff08;1&#xff09;if分支语句 Python中if语句的语法结构&#xff1a; if <条件表达式>&#xff1a;    满足条件运行的代码1    满足条件运行的代码2 代码示例&#xff1a; age 12 if age > 18:print(去上网)if 1 1 2 and :print(我满足条件了)if 1 …

【C++】C++入门(下)

引用 什么是引用&#xff1f;   引用是给一个已经存在的变量取一个别名&#xff0c;在语法上并不会给这个别名开一个空间&#xff0c;它和她引用的变量共用一个空间。但是实际上引用也是开了一块空间的&#xff0c;用来存放引用名。引用是按照指针的方式来实现的。引用语法&…

电子技术——B类输出阶

电子技术——B类输出阶 下图展示了一个B类输出阶的原理图&#xff0c;B类输出阶由两个互补的BJT组成&#xff0c;不同时导通。 原理 当输入电压 vI0v_I 0vI​0 的时候&#xff0c;两个晶体管都截止输出电压为零。当 vIv_IvI​ 上升至超过0.5V的时候&#xff0c;此时 QNQ_NQN…