JVM篇--Java内存区域高频面试题

java内存区域

1 Java 堆空间及 GC?

首先我们要知道java堆空间的产生过程: 即当通过java命令启动java进程的时候,就会为它分配内存,而分配内存的一部分就会用于创建堆空间,而当程序中创建对象的时候 就会从堆空间来分配内存,所以堆空间存放的主要是对象和数组;
而GC 其实说白了就是java虚拟机回收对象的机制,即回收无效对象的内存用于将来的分配。

2 JVM 的主要组成部分及其作用?

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
那么他们分别有啥作用呢?
首先看Class loader:根据给定的全限定名类名(如:java.lang.Object)来装载class文件到Runtime data area中的method area。其实说白了就是类加载器,简单点-作用就是通过类加载器将编译好的class文件加载到运行时数据区
Execution engine(执行引擎): 执行class中的指令
Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。
Runtime data area(运行时数据区域):这就是我们常说的JVM的内存

整体的过程:首先会通过编译器把Java代码转换成字节码源文件,之后类加载器会把字节码文件加载到内存中,即加载到运行时数据区,
但是其实字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统来去执行,因此需要特定的命令解析器即执行引擎,将字节码翻译成底层的系统指令,再交由CPU去执行
同时java代码中 可以调用其他语言的本地库接口,进行一些系统调用或者c函数的调用
在这里插入图片描述

3 说说JVM 运行时数据区? 或:说一下JVM内存模型?

jvm内存模型大致被划分为如下几个区域:
程序计数器:也就是当前线程所执行的字节码指令的行号指示器,说白了就是当前字节码执行到的位置,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令

java虚拟机栈:用于存储方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息,也是线程私有的。每个方法在执行时都会创建一个栈帧,栈帧包含了方法的局部变量表、操作数栈等信息。

本地方法栈:与 Java 虚拟机栈类似,只不过虚拟机栈是服务 Java
方法的,而本地方法栈是为虚拟机调用 Native 方法服务的

堆:用于存储对象实例和数组,它也是jvm中最大的一块内存区域,同时也是线程共享的,而堆包括年轻代和老年代,以支持垃圾回收机制。

  1. 年轻代(Young Generation):用于存放新创建的对象。年轻代又分为 Eden 区和两个 Survivor 区(通常是一个 From 区和一个 To 区),对象首先被分配在 Eden 区,经过垃圾回收后存活的对象会被移到 Survivor 区,经过多次回收后仍然存活的对象会晋升到老年代。
  2. 老年代(Old Generation):用于存放存活时间较长的对象。老年代主要存放长时间存活的对象或从年轻代晋升过来的对象。

方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据

4 什么是堆内存?

以Hotspot为例,堆内存主要由GC模块进行管理和分配,可以分为新生代和老年代,而新生代又可以分为eden区,s1区和s2区,并且他们的比例默认为8:1:1, 同时新生代和老年代的占比如下图所示
在这里插入图片描述
在使用堆内内存(on-heap memory)的时候,完全遵守JVM虚拟机的内存管理机制,采用垃圾回收器(GC)统一进行内存管理,
GC会在某些特定的时间点进行一次彻底回收,也就是Full GC,GC会对所有分配的堆内内存进行扫描,在这个过程中会对JAVA应用程序的性能造成一定影响,还可能会产生Stop The World。

5 什么是非堆内存?

通常来说方法区是非堆内存,而jdk1.8之前的方法区实现是永久代,而jdk1.8之后的方法区实现叫元空间

6 什么是堆外内存呢?

堆外内存, 常常又叫做直接内存。 和堆内内存相对应,堆外内存就是把内存对象分配在Java虚拟机的堆以外的内存
这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。
具体实现 可以 用java.nio.DirectByteBuffer对象进行堆外内存的管理和使用
那么堆外内存的优点是什么?
减少垃圾回收:因为垃圾回收会暂停其他的工作。
加快复制速度:堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作。

7 永久代和方法区又有什么区别呢?

方法区是《Java虚拟机规范》中定义的内存区域,用于存储类的结构信息(如类的字节码、常量池、字段和方法信息等),
而 Java 默认虚拟机 HotSpot 中,在 JDK 1.8 之前的版本中,是通过永久代来实现方法区的,但 JDK 1.8 之后,永久代被元空间(Metaspace)取代。
所以,总结来看,方法区是规范,而永久代(和元空间)是具体实现。

8 那么为啥用元空间来取代永久代呢?

主要原因有以下几点,

  1. 兼容JRockit --首先java官方要收购JRocket,而JRockit 中没有“永久代”的概念 所以为了更好的融合JRockit和Hotspot源码,因此取消了永久代。
  2. 其次可以提高稳定性,降低OOM的风险-因为对于永久代来说是需要设置PermSize 和 MaxPermSize 参数的,而一旦这两个值设置的不合理或者设置的过小就会频繁触发FullGC 和导致 OOM(Out of Memory,内存溢出),但是当使用元空间来替代永久代后 出现OOM的风险就大大降低了,因为元空间使用的是本地内存,也就是只和本地内存大小有关。
  3. 降低运维成本–因为用了元空间后就不在需要运维或者开发人员手动的来去设置和调整元空间的大小

9 为什么调整字符串常量池的位置?

其实主要是为了提高回收效率,便于及时的回收常量池内存,同时也是会缓解永久代空间不足的问题
首先我们要知道字符串常量池在1.7之前是放到永久代的,而永久代的回收效率是很低的,只有在fullGC的时候才会触发,而fullGC的触发也是需要再老年代的空间不足,或者永久代不足时才会进行触发,这样就导致了字符串常量池的回收效率并不高。但其实在真正的开发中,我们一般会有大量的字符串常量被创建,回收效率低反过来也会导致永久代空间不足
因此在jdk1.7之后字符串常量池被放到了堆空间中,便于及时的回收内存

10成员变量、局部变量、类变量分别存储在内存的什么地方?

  1. 类变量
    类变量是用static修饰符修饰,定义在方法外的变量,随着java进程产生和销毁。在java8之前把静态变量存放于方法区,在java8时存放在堆中

  2. 成员变量
    成员变量是定义在类中,但是没有static修饰符修饰的变量,随着类的实例产生和销毁,是类实例的一部分
    由于是实例的一部分,在类初始化的时候,从运行时常量池取出直接引用或者值,与初始化的对象一起放入堆中

  3. 局部变量
    局部变量是定义在类的方法中的变量
    在所在方法被调用时放入虚拟机栈的栈帧中,方法执行结束后从虚拟机栈中弹出,所以存放在虚拟机栈中

11 堆和栈有什么区别?

具体区别可以看以下几点
1 存放的内容
堆存放的是对象的实例和数组,而栈存放的是局部变量,操作数栈
2 再从是否私有来看
堆对于整个应用程序来说都是共享的,而栈是线程独享,所以也是线程私有。他的生命周期和线程相同
3 物理结构
堆的物理地址分配对对象是不连续的。因此性能慢些。在GC的时候也要考虑到不连续的分配,所以有各种算法。
栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。

12 什么是双亲委派模式?

说到双亲委派模式 我们先聊下什么是类加载器 以及类加载器的分类
类加载器(Class Loader)是 Java 虚拟机(JVM)的重要组成部分,负责将字节码文件加载到内存中并转换为可执行的类
而类加载器大致可以分为四种
启动类加载器:加载 JDK 中 lib 目录中 Java 的核心类库,即$JAVA_HOME/lib目录。
扩展类加载器:加载 lib/ext 目录下的类;
应用程序类加载器:加载我们写的应用程序;
自定义类加载器:根据自己的需求定制类加载器。

而 双亲委派模型是 Java 类加载器的一种工作机制。
它是指当一个类加载器需要加载一个类时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。
双亲委派模型的优点是啥?
避免重复加载类:比如 A 类和 B 类都有一个父类 C 类,那么当 A 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了。
提高安全性使用双亲委派模型也可以保证了 Java 的核心 API 不被篡改,如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户自己提供的因此安全性就不能得到保证了。

那么如何打破双亲委派机制呢?
1.自定义类加载,重写loadclass方法
因为双亲委派的机制都是通过这个方法实现的,这个方法可以指定类通过什么类加载器来进行加载,所有如果改写他的加载规则,相当于打破双亲委派机制

2.使用线程上下文类
双亲委派模型的第二次“破坏”是由这个模型自身的缺陷所导致的,双亲委派很好的解决了各个类加载器的基础类统一问题,基础类之所以“基础”,是因为他们总被用户代码所调用,但是如果基础类又要重新调用用户代码,那咋办?
比如说JNDI是java的标准服务,它的代码是由启动类加载器进行加载的,但是jndi的作用就是进行资源的集中管理和查找,它需要调用由开发人员开发在classpath下的类代码,但是启动类加载器不会进行加载。
所以引入线程上下类加载器,通过java.lang.Thread类的setContextClassLoader()方法进行设置。如果创建线程是还未设置,它会从父线程继承一个,如果在应用程序全局范围内没有设置,那么这个线程上下类加载器就是应用程序类加载器。
那么这样JNDI服务使用这个线程上下类加载器去加载所需的spi代码,也就是父类加载器请求子类加载器去完成类加载的动作,这个实际是打通了双亲委派的逆向层次结构。

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

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

相关文章

2024--Django平台开发-Redis集群(十一)

内容回顾 主从复制。 哨兵:实例启动了,哨兵节点没启动,Python通过redis-py连接报错。一定要确保实例节点和哨兵节点都启动了。 搭建集群用的是虚拟机的多台centos服务器,你在跟着学习的时候,一定要全部都是虚拟机&am…

5.矩阵分析

矩阵分析 文章目录 矩阵分析一、方阵范数1.1 矩阵范数1.2 与矩阵乘积相容的矩阵范数【定义】自相容范数 / 方阵范数 1.3 与向量范数相容的矩阵范数【定义】矩阵范数与向量范数相容【定理】任意自相容范数必存在与它相容的向量范数 二、算子范数2.1 方阵的算子范数【定理】由向量…

PVE虚拟机安装qemu guest agent

pve虚拟机安装guest agent,使web平台可以直接显示虚拟机的ip,方便管理。 一、虚拟机需开启Qemu代理 首先,虚拟机需开启Qemu代理,需要关闭虚拟机再启动虚拟机并安装agent。网上有些文章说要把网卡配置为virtio,经测试是…

可协作植物管理工具HortusFox

什么是 HortusFox ? HortusFox 是一个自托管的协作植物管理系统,您可以在自己的环境中使用它来管理所有的植物。您可以添加植物,并附带各种详细信息和照片,并将它们分配到环境中的位置。系统提供了一个仪表板,显示所有…

小程序系列--6.全局配置

一. 全局配置文件及常用的配置项 二、window 1. 小程序窗口的组成部分 2. 了解 window 节点常用的配置项 3. 设置导航栏的标题 4. 设置导航栏的背景色 5. 设置导航栏的标题颜色 6. 全局开启下拉刷新功能 7. 设置下拉刷新时窗口的背景色 8. 设置下拉刷新时 loading 的样…

Git 使用与问题记录 二(公司快速上手版)

写在前面 记录自己学习的内容,方便后面忘记的时候查看。给像我一样的新手提供一点参考 正文 上一章已经安装好了Git,如何使用呢。我这里会分享两种办法,第一种是在VS2022中克隆代码,修改和提交;第二种是用命令提交。…

【计算机网络】TCP原理 | 可靠性机制分析(四)

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】 本专栏旨在分享学习计算机网络的一点学习心得,欢迎大家在评论区交流讨论💌 这里写目录标题 &#x1…

C函数详解 | 函数的作用、定义与声明、函数的调用、函数与指针

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。关…

RISC-V是如何与X86、ARM三分天下

目录 1.行业CPU指令集格局 2.汽车中的RISC-V进展 2.1 国际进展 2.2 国内进展 3.小结 2023年3月2日,在平头哥牵头举办的玄铁RISC-V生态大会上,工程院院士倪光南表示,基于RISC-V模块化、可扩展、容易定制、不受垄断制约等优势,…

电商API接口|Javascript抓取京东、淘宝商品数据

“ 不知怎么建站?就找怎么建站! ” 背景: EDI许可证网站和ICP许可证网站需要有丰富的商品数据来应付EDI、ICP许可证下证审核。下面介绍的这种方法是我之前主要的抓取数据的方法,大概用了一年多。这几天又对这个方法进行了一些优…

11.云原生分布式数据库之TIDB

云原生专栏大纲 文章目录 为什么使用TIDB后端视角运维视角基础架构视角 TiDB Operator 简介软件版本要求部署tidbTIDB工具helm常用命令TIDB学习推荐资料 为什么使用TIDB 从后端视角、运维视角和基础架构视角来看,使用 TiDB 作为数据库系统可以获得分布式架构、高可…

学习Java API(二):基础知识点一文通✅

推荐阅读 智能化校园:深入探讨云端管理系统设计与实现(一) 智能化校园:深入探讨云端管理系统设计与实现(二) 文章目录 推荐阅读正则表达式正则表达式语法捕获组和分组matches 和 lookingAt 方法split方法r…

LeeCode前端算法基础100题(20)找出字符串中第一个匹配项的下标

一、问题详情: 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 示例 1: 输入:haystack = "sadbutsad", needle = "s…

安全生产管理平台——革新传统安全生产管理方式,重塑企业安全文化

安全生产管理在现代企业中占据着至关重要的地位。传统的安全生产管理方式虽然在一定程度上能够保障企业的生产安全,但随着企业规模的不断扩大和生产环境的日益复杂,其局限性也愈发凸显。而安全生产管理平台的出现,正是为了解决这一问题。 平台…

从六西格玛到DFSS:提升企业创新能力的关键方法——张驰咨询

DFSS(Design for Six Sigma,即六西格玛设计)是一种结合了六西格玛思想和创新设计方法的质量管理方法。它的目标是在产品或服务的设计阶段,通过优化设计过程和减少变异性,以确保产品或服务达到高质量水平,满…

Linux多网卡绑定实现负载均衡详解

将多块网卡绑定同一IP地址对外提供服务,可以实现高可用或者负载均衡。直接给两块网卡设置同一IP地址是不可以的。通过 bonding,虚拟一块网卡对外提供连接,物理网卡的被修改为相同的MAC地址。 目录 1、bond的作用 2、Bonding聚合链路工作模…

反射助你无痛使用Semantic Kernel接入离线大模型

本文主要介绍如何使用 llama 的 server 部署离线大模型,并通过反射技术修改 Semantic Kernel 的 OpenAIClient 类,从而实现指定端点的功能。最后也推荐了一些学习 Semantic Kernel 的资料,希望能对你有所帮助。 封面图片: Dalle3 …

软信天成:数据安全管理解决方案分享

近年来,随着数据环境日趋复杂多变和潜在的数据隐私泄露风险潜伏,如何确保企业数据安全已成为众多企业亟待面对与妥善处理的重要问题。 为了应对这一严峻的现实挑战,软信天成凭借专业的知识体系和丰富的实战经验积累,总结出了一套…

Java多线程并发篇----第十四篇

系列文章目录 文章目录 系列文章目录前言一、ReadWriteLock 读写锁二、共享锁和独占锁三、重量级锁(Mutex Lock)四、轻量级锁前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给…

Spring MVC中的一些常用注解

目录 RequestMapping 实现路由映射 限制请求方式 PathVariable 从url中获取变量的值 更改绑定参数的名字 RequestParam 可以传递集合 更改绑定参数的名字 可修改是否为必传参数 RequestBody 获取请求正文的内容 可修改是否为必传参数 RequestPart 可以支持上传…