图解Java数组的内存分布

我们知道,访问数组元素要通过数组索引,如:

arr[0]

如果直接访问数组,比如:

int[] arr1 = {1};
System.out.println(arr1);

会发生什么呢?

在这里插入图片描述
打印的是一串奇怪的字符串:[I@16b98e56

这个字符串是Java在打印对象时的特殊输出,包含如下三部分信息:

  • 对象类型,如上图的[符号表示是数组类型,I表示整形数组
  • @是分隔符,没有实际意义
  • 16b98e56是堆内存地址,通过这个变量找到数组后,才能对其进行访问和修改

也就是说,数组变量存储的不是数组,而是一个地址,这个地址指向了哪里呢

要回答这个问题,首先要了解下Java的内存分布原理。

一,Java的内存分布

1,Java虚拟机内存划分

Java将虚拟机内存分为如下几个区域:

  • 本地方法栈
  • 寄存器
  • 虚拟机栈
  • 方法区/元空间

这样需要注意的是:从JDK8开始,Java取消了方法区,将方法区拆分到堆区、堆外区、元空间,增加一个元空间区,同时增加了堆外内存的使用。

JDK8前的内存分布:

在这里插入图片描述

JDK8的内存分布:

在这里插入图片描述

2,基本类型和引用类型的内存分布差异

特别来看下堆和栈,这是最为核心、重要的两个内存区域:
在这里插入图片描述

根据堆栈知识来理解下基本类型和引用类型的不同,这两种类型的变量值都存储在栈内存,但变量值本身的意义有较大的区别:

  • ①基本类型变量的值直接存储在栈内存,不涉及堆内存
  • ②引用类型变量的值在栈内存存储的是对象的地址,指向对象在堆内存的地址

基本类型变量的内存分布(仅涉及栈内存):

在这里插入图片描述

引用类型变量的内存分布(涉及栈和堆):

在这里插入图片描述

二,一个数组的内存分布

对于如下代码:

int[] arr = new int[2];
sout(arr);
sout(arr[0]);
sout(arr[1]);

逐行解释如上代码:

第一行代码声明并初始化一个数组arr,Jvm会做两件事:

  • ①在栈内存分配一块内存,存储数组对象地址
  • ②在堆内心分配一块内存,存储数组元素

第二行代码打印数组地址

第三行代码访问数组第一个元素,Jvm会根据栈内存中数组变量存储的地址,找到堆内存中数组对象,访问并读取第一个元素,然后打印

第四行代码和第三行作用相同,不同的是读取的是第二个元素

在这里插入图片描述

三,两个或多个不同数组的内存分布

当我们创建两个或两个以上的不同数组时,如图所示,会在栈内存中创建两个变量,这两个变量存储两个不同的堆内存地址,指向堆中不同的两个内存区域,存放着不同的两个数组对象:

在这里插入图片描述

当我们打印这两个数组变量时:

System.out.println(arr);
System.out.println(arr2);

输出的地址不相,分别是:[I@0x110fa7f48[I@0xbec966a

三,两个变量指向同一个数组的内存分布

int[] arr1 = {11,22};
int[] arr2 = arr1;
sout(arr1);
sout(arr2);
sout(arr1[0]);
sout(arr2[0]);
arr2 = new int[]{11, 22}

逐行解释如上代码:

第一行代码声明并初始化一个数组arr1,Jvm做两件事:

  • ①在栈内存分配一块内存,存储数组对象地址
  • ②在堆内心分配一块内存,存储数组元素

第二行代码声明并初始化一个数组arr2,Jvm做两件事:

  • ①在栈内存分配一块内存
  • ②将arr1变量的值复制给arr2

此时,变量arr1和arr2指向了同一块堆内存

在这里插入图片描述

执行第三行第四行代码:

sout(arr1);
sout(arr2);

会打印两个一样的值:[I@0x0011

第五行代码访问数组arr1第一个元素,Jvm会根据栈内存中数组变量存储的地址,找到堆内存中数组对象,访问并读取第一个元素,然后打印。

第六行代码访问数组arr2第一个元素,因为arr1arr2指向同一个数组,所以打印结果和第五行一致。

接下来,请大家思考,执行第七行代码arr2 = new int[]{11, 22}后,会出现什么情况呢?

尽管这个数组的元素个数、值都和arr1一致,但是Jvm还是会在堆区创建一个新的数组,并将arr2的值覆盖为新的数组对象的地址:

在这里插入图片描述

如果再次执行第三行第四行代码:

sout(arr1);
sout(arr2);

打印的结果就不再相同了,分别是[I@0x33bab[I@0x453fe

五,结论

  • ①数组变量分配在栈内存,存储的是对象地址,这个地址指向堆内存
  • ②数组对象(数组大小、所有数组元素)本身存储在堆内存中
  • ③访问和修改数组要通过数组变量存储的地址,找到数组对象,然后访问和修改其中的元素值
  • ④如果两个数组变量指向同一个数组对象,则通过变量访问的是同一个对象。如果之后其中一个数组指向另一个对象,通过这两个变量访问的就不再是同一个对象了

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

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

相关文章

强化训练:day11(游游的水果大礼包、 买卖股票的最好时机(二)、倒置字符串)

文章目录 前言1. 游游的水果大礼包1.1 题目描述1.2 解题思路1.3 代码实现 2. 买卖股票的最好时机(二)2.1 题目描述2.2 解题思路2.3 代码实现 3. 倒置字符串3.1 题目描述3.2 解题思路3.3 代码实现 总结 前言 1. 游游的水果大礼包   2. 买卖股票的最好时机(二)   3. 倒置字符…

【车道线网络,给予他预训练模型权重,为什么继续训练得不到更好的权重参数,反而会出现检测效果的下降?】】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、检测效果的下降?解决方案总结 车道线网络,给予他预训练模型权重,为什么继续训练得不到更好的权重参数,反而会出现…

NLP(20)--知识图谱

前言 仅记录学习过程,有问题欢迎讨论 基于LLM的垂直领域问答方案: 特点:不是通用语料;准确度要求高,召回率可以低(转人工);拓展性和可控性(改变特定内容的回答&#xf…

std::mutex

结论: 最终std::mutex 会调用pthread_mutex_t 相关接口 1 std::mutex 定义封装关键数据:typedef __gthread_mutex_t #ifdef _GLIBCXX_HAS_GTHREADS// Common base class for std::mutex and std::timed_mutexclass __mutex_base{protected:typedef __g…

数据结构初阶 栈

一. 栈的基本介绍 1. 基本概念 栈是一种线性表 是一种特殊的数据结构 栈顶:进行数据插入和删除操作的一端 另一端叫做栈底 压栈:插入数据叫做压栈 压栈的数据在栈顶 出栈: 栈的删除操作叫做出栈 出栈操作也是在栈顶 栈遵循一个原则 叫做…

Python深度学习:【模型系列】一文搞懂Transformer架构的三种注意力机制

文章目录 1. 什么是注意力机制?2. Transformer 的注意力层2.1 注意力机制基础2.2 理解Q,K,V2.3 交叉注意力层2.4 全局自注意力层2.5 因果注意力层3. 位置编码4. 多头注意力机制5. 总结1. 什么是注意力机制? 注意力机制最初受到人类视觉注意力的启发,目的是让模型在处理大…

JavaEE:Servlet创建和使用及生命周期介绍

目录 ▐ Servlet概述 ▐ Servlet的创建和使用 ▐ Servlet中方法介绍 ▐ Servlet的生命周期 ▐ Servlet概述 • Servlet是Server Applet的简称,意思是 用Java编写的服务器端的程序,Servlet被部署在服务器中,而服务器负责管理并调用Servle…

2024.5.21 作业 xyt

今日课堂内容&#xff1a;域套接字 TCP流式套接字 //服务器 #include <myhead.h> int main(int argc, const char *argv[]) {//1、为通信创建一个端点int sfd socket(AF_UNIX, SOCK_STREAM, 0);//参数1&#xff1a;说明使用的是ipv4通信域//参数2&#xff1a;说明使用…

ffpmeg之avformat_network_init和avdevice_register_all函数

avformat_network_init 如果利用ffpmeg库拉取视频流或者通过http协议打开视频文件播放&#xff0c;涉及到网络IO操作的&#xff0c;在应用程序之前首先需要调用avformat_network_init函数&#xff0c;该函数调用后就实现了对ffmpeg模块IO的一些初始化&#xff0c;后续就可以利…

HTML静态网页成品作业(HTML+CSS)——动漫海绵宝宝介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

【前端笔记】记录一个能优化Echarts Geo JSON大小的网站

前端在使用Echarts等可视化图表库会不可避免遇到的问题&#xff0c;渲染地图的数据太大。 而有那么一个网站能给予这个问题一个解决方案&#xff1a;链接在此 使用方法很简单&#xff0c;首先先进入网站&#xff0c;如果进入了会是这个页面&#xff1a; 接着&#xff0c;选择一…

代码随想录算法训练营第四十三天|

518.零钱兑换II 典型的完全背包问题&#xff0c;但这里是求有多少种组合方式&#xff0c;所以递推公式变为 dp[j] dp[j - coins[i]]; 377. 组合总和 Ⅳ 也是完全背包问题&#xff0c;但是需要求排列而不是组合&#xff0c;所以需要先遍历背包容量&#xff0c;再遍历物品。 …

HCIP的学习(25)

VLAN间通讯技术 使用多臂路由的方式 ​ 路由器的物理接口默认是不识别802.1Q标签的&#xff0c;所以&#xff0c;交换机连接路由器的接口在发送数据帧时&#xff0c;应该将标签剥离。----一般常使用Access接口配置。 单臂路由 ​ 所谓的单臂路由&#xff0c;实际上试讲路由器…

【主流分布式算法总结】

文章目录 分布式常见的问题常见的分布式算法Raft算法概念Raft的实现 ZAB算法Paxos算法 分布式常见的问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;…

Docker是什么?使用场景作用及Docker的安装和启动详解

目录 Docker是什么&#xff1f; Docker的发展 Docker的安装 Docker使用 Docker的运行机制 第一个Docker容器 进入Docker容器 客户机访问容器 Docker是什么&#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker …

记录深度学习GPU配置,下载CUDA与cuDnn

目标下载: cuda 11.0.1_451.22 win10.exe cudnn-11.0-windows-x64-v8.0.2.39.zip cuda历史版本网址 CUDA Toolkit Archive | NVIDIA Developer 自己下载过11.0.1版本 点击下载local版本,本地安装,有2个多GB,很大,我不喜欢network版本,容易掉线 cuDnn https://developer.nvi…

设置AXI主寄存器切片和AXI数据FIFO

设置AXI主寄存器切片和AXI数据FIFO 打开MHS文件&#xff0c;并为每个AXI主机设置启用寄存器切片/启用数据FIFO。到 确定正确的设置&#xff0c;使用下表中的信息搜索MHS。 进行搜索时&#xff0c;将<intf_name>替换为相关的BUS_INTERFACE名称。 例如&#xff0c;BUS_INTE…

Docker部署SpringBoot项目(jar包+Mysql)

部署Java项目 项目准备准备Java项目镜像准备配置网络 部署项目细节展示 项目准备 准备Java项目 hmall项目是一个maven聚合项目&#xff0c;使用IDEA打开hmall项目&#xff0c;查看项目结构如图&#xff1a; 我们要部署的就是其中的hm-service&#xff0c;其中的配置文件采用…

《一地霜白》读书笔记

1.3.6 街灯明灭&#xff0c;勾缀成行&#xff0c;为了生者与死者 “很多年过去了。回头看&#xff0c;沿着一排暗中的街灯&#xff0c;两三盏灭了&#xff0c;郁闷中有意外的欣喜&#xff1a;街灯明灭&#xff0c;勾缀成行&#xff0c;为了生者与死者。” 童年、青少年在人的…