JVM堆栈的区别、分配内存与并发安全问题、对象定位

一、堆和栈的区别

堆(Heap)和栈(Stack)是两种基本的数据结构,它们在内存管理、程序执行流程控制等方面扮演着重要角色。在编程语言尤其是Java这样的高级语言环境中,堆和栈的概念被用来描述程序运行时的内存布局。以下是它们之间的一些关键区别:

1. 物理地址

        堆的物理地址分配对对象是不连续的。因此性能慢些。在GC的时候也要考虑到不连续的分配,所以有各种算法。比如,标记-消除,复制,标记-压缩,分代 (即新生代使用复制算法,老年代使用标记——压缩)

        栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。

2. 内存分别

         堆因为是不连续的,所以分配的内存是在运行期确认的,因此大小不固定。一般 堆大小远远大于栈。

        栈是连续的,所以分配的内存大小要在编译期就确认,大小是固定的。

3. 存放的内容

        堆存放的是对象的实例和数组。因此该区更关注的是数据的存储

        栈存放:局部变量,操作数栈,返回结果。该区更关注的是程序方法的执行。

        PS: 1. 静态变量放在方法区 2. 静态的对象还是放在堆。 

4. 程序的可见度

        堆对于整个应用程序都是共享、可见的。

        栈只对于线程是可见的。所以也是线程私有。他的生命周期和线程相同。

二、内存分配与处理并发安全问题

1. 内存分配

类加载完成后,接着会在Java堆中划分一块内存分配给对象。内存分配根据Java 堆是否规整,有两种方式:

        1. 指针碰撞:如果Java堆的内存是规整,即所有用过的内存放在一边,而空闲的的 放在另一边。分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小 相等的距离,这样便完成分配内存工作。

        2. 空闲列表:如果Java堆的内存不是规整的,则需要由虚拟机维护一个列表来记录那些内存是可用的,这样在分配的时候可以从列表中查询到足够大的内存分配给对象,并在分配后更新列表记录。 选择哪种分配方式是由 Java 堆是否规整来决定的,而 Java 堆是否规整又由所 采用的垃圾收集器是否带有压缩整理功能决定 

2. 处理并发安全问题

 对象的创建在虚拟机中是一个非常频繁的行为,哪怕只是修改一个指针所指向的位置,在并发情况下也是不安全的,可能出现正在给对象 A 分配内存,指针还没来得及修改,对象 B 又同时使用了原来的指针来分配内存的情况。解决这个问题有两种方案: 

        1. 对分配内存空间的动作进行同步处理(采用 CAS + 失败重试来保障更新操作的原子性)

        2. 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在 Java 堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。哪个线程要分配内存,就在哪个线程的 TLAB 上分配。只有 TLAB 用完并分配新的 TLAB 时,才需要同步锁。通过-XX:+/-UserTLAB参数来设定虚拟机是否使用TLAB。

三、对象定位

Java程序需要通过 JVM 栈上的引用访问堆中的具体对象。对象的访问方式取决于 JVM 虚拟机的实现。目前主流的访问方式有 句柄直接指针 两种方式。

        指针: 指向对象,代表一个对象在内存中的起始地址。

        句柄: 可以理解为指向指针的指针,维护着对象的指针。句柄不直接指向对象,而是指向对象的指针(句柄不发生变化,指向固定内存地址),再由对象的指针指向对象的真实内存地址。

1. 句柄访问

Java堆中划分出一块内存来作为句柄池,每个对象在堆中都有一个对应的句柄。句柄包含两部分信息:对象实例数据的指针和类型数据(如类的元数据)的指针。而栈上的引用变量存储的是句柄池中句柄的地址。具体构造如下图所 示:

 优势:如果对象被移动(如垃圾回收时),只需要修改句柄池中的实例数据指针即可,栈上的引用和句柄池中的类型数据指针不需要改变,这降低了维护引用的开销。

缺点:每次访问对象都需要两次间接寻址(先通过引用找到句柄,再通过句柄找到实际对象),这可能会增加访问时间。

2. 直接指针

如果使用直接指针访问,引用中存储的直接就是对象地址,那么Java堆对象内部的布局中就必须考虑如何放置访问类型数据的相关信息

优势:速度更快,节省了一次指针定位的时间开销。由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是非常可观的执行成本。

缺点:如果对象被移动,所有指向该对象的引用都必须更新,这在垃圾回收时可能会增加一定的开销。

Java虚拟机的具体实现(如HotSpot JVM)可以选择使用其中一种方式,或者根据情况动态选择。早期的HotSpot JVM倾向于使用直接指针访问以提高性能,但在某些特定配置或JVM版本中,可能会采用句柄访问以适应特定场景的需求。

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

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

相关文章

【计算机网络】TCP报文详解

认识TCP报头 其实协议的形式都是一个结构化的数据,TCP协议也不例外。一起来看看TCP协议的报头是怎么样的。 以上就是TCP报头,实际上是一个结构化的数据,也就是一个结构体。例如: struct tcp_hdr {unsigned int stc_port : 16;un…

分布式光纤测温DTS与红外热成像系统的主要区别是什么?

分布式光纤测温DTS和红外热成像系统在应用领域和工作原理上存在显著的区别,两者具有明显的差异性。红外热成像系统适用于表现扩散式发热、面式场景以及环境条件较好的情况下。它主要用于检测物体表面的温度,并且受到镜头遮挡或灰尘等因素的影响会导致失效…

英语学习笔记35——Our village

Our village 我们的村庄 词汇 Vocabulary photograph n. 照片 通常说:photo 复数:photos     picture 复数:pictures 搭配:take a photo 照相 以o结尾的单词复数es的: potato —— potatoes tomato —— tomatoe…

Prometheus+Grafana监控MySQL

一、准备 grafana服务器:192.168.48.136Prometheus服务器:192.168.48.136被监控服务器:192.168.48.134、192.168.48.135查看时间是否同步 二、安装prometheus server 【2.1】安装 # 解压安装包 tar -zxvf prometheus-2.52.0.linux-amd64.t…

Element UI 日期组件自定义可选范围

官网地址 :Element - The worlds most popular Vue UI framework 自定义方式: 在data()函数中定义 // 日期选择器可选范围expireTimeOption: {disabledDate: time > {// 判断是否是在任务时间段if (this.isTaskRandTime(time)…

数字人直播系统源码,不需要高价购买,只需这个价!

在技术领域,系统源码的价格往往令人咋舌,尤其是涉及到高端应用如数字人直播系统时。那么,一套数字人直播系统源码到底需要多少钱?面对高昂的价格,是否还值得进入这个行业? 首先,我们要认识到数…

UE5-不同材质上脚步声

主要是用物理材质给不同的材质加一个标签 创建材质 首先去设置里面创建几个地形材质名称,我这里创建了Grass,Rock,Wood,Water (就是名字而已) 然后创建物理材质(物理材质可以添加到现有的普通…

虚拟仿真实训平台助力院校人才培养与产业发展共赢

一、虚拟仿真实训平台简单介绍 虚拟仿真实训平台适用于虚拟仿真实训教学场所,几乎兼容所有虚拟仿真实训显示设备,能够完成虚拟仿真实训资源进行跨专业、跨院校、跨地域的统筹管理。且虚仿平台具备虚拟仿真实训教学过程的监控分析及虚拟仿真实训资源集合…

WPF中的隧道路由和冒泡路由事件

文章目录 简介:一、事件最基本的用法二、理解路由事件 简介: WPF中使用路由事件升级了传统应用开发中的事件,在WPF中使用路由事件能更好的处理事件相关的逻辑,我们从这篇开始整理事件的用法和什么是直接路由,什么是冒…

探索大数据在信用评估中的独特价值

随着我国的信用体系越来越完善,信用将影响越来越多的人。现在新兴的大数据信用和传统信用,形成了互补的优势,大数据信用变得越来越重要,那大数据信用风险检测的重要性主要体现在什么地方呢?本文将详细为大家介绍一下,…

深入理解并打败C语言难关之一————指针(3)

前言: 昨天把指针最为基础的内容讲完了,并且详细说明了传值调用和传址调用的区别(这次我也是做到了每日一更,感觉有好多想写的但是没有写完),下面不多废话,下面进入本文想要说的内容 目录&#…

怎么提升机器人外呼的转化效率

在某些情况下,如市场调查、产品推广等,语音机器人可以高效地完成大量的呼叫任务,并能通过预设的语音脚本和智能识别功能,初步筛选和分类潜在客户。此时,不转人工可能更为高效和经济。 然而,在一些需要深度沟…

停止游戏中的循环扣血显示

停止游戏中循环扣血并显示的具体实现方式会依赖于你的代码结构和游戏的逻辑。通常情况下,你可以通过以下方式来实现停止循环扣血和显示: 1、问题背景 在使用 Python 代码为游戏开发一个生命值条时,遇到了一个问题。代码使用了循环来减少生命…

【PLG洞察】|向Figma学习如何打造标杆客户和实施分销策略

Figma是一款功能强大的在线协同设计工具,它主要被用于界面设计、原型设计和用户体验设计。作为国外知名的saas企业,对标国内的saas蓝海,它的增长实在惊人!据称,Figma2020年的收入已达$75M, 2021年6月,美国的…

Kafka流计算培训:打造Kafka技术专家,引领大数据未来

Kafka流计算培训课程是一门旨在帮助大数据从业人员和欲从事Kafka技术的人员快速掌握Kafka核心技术的专业培训项目。 在这个3天的课程中,我们将全面细致地讲解Kafka流计算软件的配置、Kafka流计算开发和流计算管道设计等内容,让学员能够在实际工作中灵活…

C++的异常捕获

目录 C语言的异常处理方式 C的异常处理方式 异常的抛出与捕获 抛出与捕获原则 异常安全 C语言的异常处理方式 1、终止程序 常见形式:assert 缺陷:太过强硬,如果发生内存错误,或者除0语法错误等就会直接终止程序 2、返回错误码…

2024年新闻传播、社会科学与公共艺术国际会议(ICJSSPA2024)

2024年新闻传播、社会科学与公共艺术国际会议(ICJSSPA2024) 会议简介 2024年新闻传播、社会科学与公共艺术国际会议(ICJSSPA2024)即将在上海举行。这项国际活动将汇集来自世界各地的新闻和传播学者、社会科学研究精英和公共艺术领域的创新者。会议旨在搭建一个开放包容的交…

MySQL Online DDL原理解读

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 💥💥个人主页:奋斗的小羊 💥💥所属专栏:C语言 🚀本系列文章为个人学习…

Idea jdk配置的地方 启动时指定切换的地方

jdk 配置的地方 项目sdk 所在位置 管理添加或删除的地方,增加后,可以在在上面切换 启动时指定版本

UE4中性能优化工具合集

UE4中性能优化工具合集 简述CPUUnreal InsightUnreal ProfilerSimpleperfAndroid StudioPerfettoXCode TimeprofilerBest Practice GPUAdreno GPUMali GPUAndroid GPU Inspector (AGI) 内存堆内存分析Android StudioLoliProfilerUE5 Memory InsightsUnity Mono 内存MemreportRH…