Java的内存机制

2023-11-11

1.Java的内存机制

 Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁。分配给它的内存会被回收,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

  堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

代码实例Test01:单个对象创建

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+"年龄"+age);
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person per=new Person();
    }
}

在上述程序中实例化了一个对象per,在实例化对象的过程中需要在内存中开辟空间,这其中就包括栈内存和对内存。具体的内存分配如下图所示:

我们可以从上图中发现,对象名称per被保存在了栈内存中(更加准确的说法是,在栈内存中保存的是堆内存空间的访问地址),而对象的具体内容,比如属性name和age,被保存在了堆内存中。因为per对象只是被实例化,还没有具体被赋值,所以都是默认值。字符串的默认值为null,int类型的默认值为0。前面也已经提到,堆内存空间必须使用new关键字才能开辟。

代码实例Test02:多个对象创建

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

public class Test02 {
    public static void main(String[] args) {
        Person per1=new Person();
        Person per2=new Person();
        
        per1.name="张三";
        per1.age=30;
        per2.name="李四";
        per2.age=33;
        
        per1.tell();
        per2.tell();
    }
}

关键概念:类跟数组一样,都是属于引用类型,引用类型就是指一堆对内存可以同时被多个栈内存指向。下面来看一下引用传递的简单实例。

代码实例Test03:对象引用传递1

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

public class Test03{
    public static void main(String[] args) {
        Person per1=new Person();
        Person per2=per1;
        
        per1.name="张三";
        per1.age=30;
        per2.age=33;
        
        per1.tell();
        per2.tell();
    }
}

程序运行结果为:

姓名:张三,年龄:33
姓名:张三,年龄:33

从程序的运行结果可以发现,两个对象输出的内容一样,实际上所谓的引用传递,就是将一个堆内存空间的使用权交个多个栈内存空间,每个栈内存空间都可以修改堆内存空间的内容,此程序的内存分配图如下所示:

注意:上述实例中对象per2没有堆内存空间,这是因为对象per2只进行了声明操作,也没有进行实例化操作。只有使用new关键字实例化以后才会有对内存空间。

代码实例Test04:对象引用传递2

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

public class Test04 {
    public static void main(String[] args) {
        Person per1=new Person();
        Person per2=new Person();

        per1.name="张三";
        per1.age=30;
        per2.name="李四";
        per2.age=33;
        per2=per1;
        
        per1.tell();
        per2.tell();
    }
}

上述程序运行结果为:

姓名:张三,年龄:30
姓名:张三,年龄:30

从程序的输出结果可以发现可Test03一样。不过内存分配发生了一些变化,具体如下所示:

注意点:

  1. Java本身提供垃圾收集机制(Garbage Collection,GC),会不定期施放不用的内存空间,只要对象不用了,就会等待GC释放空间,如上面堆内存中的name="李四";age=33。
  2. 一个栈内存只能指向一个对内存空间,如果要想再指向其他的堆内存空间,则必须先断开已有的指向才能分配新的指向。

java中常用的内存区域

在java中主要存在4块内存空间,这些内存的名称及作用如下:

  1. 栈内存空间:保存所有的对象名称(更准确地说是保存了引用的堆内存空间的地址)
  2. 堆内存空间:保存每个对象的具体属性内容。
  3. 全局数据区:保存static类型的属性。
  4. 全局代码区:保存所有的方法定义。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java的内存机制 的相关文章

随机推荐

  • 记录STM32各类串口中断实验

    STM32F407VG使用cubemx LL库 波特率115200 一位停止位 无校验 单片机初始化串口一 PA8高速推挽输出 使用逻辑分析仪100M采样捕获各类串口中断触发时的波形 首先是喜闻乐见的RXNE 理论是只要串口成功接收一byt
  • Cache 和 Buffer 有什么区别

    Cache 和 Buffer 有什么区别 转载 talkwithtrend https mp weixin qq com s YsEOBVS7fXgrGXnXH1I0MQ Cache和Buffer简单的说 Cache是加速 读 而buffe
  • android自定义可缩放,移动图像裁剪框

    在实际项目中 经常要制作一个简易的图像裁剪功能 即获取一张图片 并用一个遮罩层选择目标范围并截取保存的功能 如下图所示 在此分享下该自定义视图的制作过程 需求说明 整一个视图包含一个透明的遮罩层 一个透明带白色边框的矩形 要实现的功能是 点
  • oracle 问题 :Cause: java.sql.SQLSyntaxErrorException: ORA-00933: SQL 命令未正确结束

    使用mysql时使用的sql语句常有 结尾的语句 但oracle中不能出现 结尾 因为oracle解析器很严谨 不支持 结尾语句解析
  • C基础day6(2023.7.6)

    一 Xmind整理 二 课上练习 练习1 循环嵌套 三个循环结构可以任意嵌套 include
  • Python爬虫分析唯品会商品数据 +数据可视化

    目录 前言 数据来源分析 1 明确需求 2 抓包分析 通过浏览器自带工具 开发者工具 代码实现步骤 发送请求 gt 获取数据 gt 解析数据 gt 保存数据 发送请求 解析数据 保存数据 数据可视化 先读取数据 泳衣商品性别占比 商品品牌分
  • Springmvc+mybatis+Dubbo+ZooKeeper+Redis+KafKa

    开发工具 1 Eclipse IDE 采用Maven项目管理 模块化 2 代码生成 通过界面方式简单配置 自动生成相应代码 目前包括三种生成方式 增删改查 单表 一对多 树结构 生成后的代码如果不需要注意美观程度 生成后即可用 技术选型 只
  • Androidstudio快捷操作之多选

    如图 想要批量复制属性名 不需要一个一个的复制 只需按住alt 鼠标左键从上往下拉 将光标定位在每个属性名的前面 再按ctrl w就可以选中所有光标后面的单词了
  • QT里使用sqlite的问题,好多坑

    1 我使用sqlite 开发机上好好的 测试机上却不行 后来发现是缺少驱动 Driver not loaded Driver not loaded 代码检查了又检查 发现应该是缺少dll文件 系统不提示 是自己使用 QMessageBox
  • c语言基础五子棋,十分的易懂理解,详细解释,容易上手

    前言 提示 经过b站和视频学习后编程 提示 以下是本篇文章正文内容 下面案例可供参考 文章目录 前言 五子棋 头文件 展示棋盘 display 下棋 PlayMove 主体函数 game 完整代码 五子棋 本篇博客主要写了关于c语言的五子棋
  • MySQL主从搭建-Centos实战

    目录 一 规划说明 二 主节点安装MySQL 1 下载MySQL和安装 2 启动Mysql 设置root密码 允许远程登录 三 副节点安装MySQL 参考主节点 四 主节点配置 1 配置my cnf 修改默认存储目录为指定目录 data 下
  • 解决SQL查询总是超时已过期

    解决SQL查询总是超时已过期 在WIN8里提示 OLE DB 或 ODBC 错误 查询超时已过期 HYT00 1 由于数据库设计问题造成SQL数据库新增数据时超时 症状 Microsoft OLE DB Provider for SQL S
  • web前端页面适配方法

    流式布局 就是百分比布局 非固定像素 内容向两侧填充 理解成流动的布局 称为流式布局 视觉窗口 viewport 是移动端特有 这是一个虚拟的区域 承载网页的 承载关系 浏览器 gt viewport gt 网页 适配要求 1 网页宽度必须
  • c++基础十一(跳转语句)

    跳转语句 1 break 2 continue 3 goto 1 break 作用 跳出循环结构和选择结构 1 switch语句中 用于终止case并跳出switch语句 2 在循环结构中 用于跳出当前循环 3 在嵌套循环语句中 跳出最近的
  • 企业微信 => 接入第三方vue应用 第三阶段:企业微信使用JSSDK

    目录 使用说明 官方文档不会告诉你的内容 都是会踩的坑 一 我采用的混入方法去使用这个官方SDK 二 可能会遇到的坑 前提 我们开发的是三方应用 不是内部应用 使用说明 所有的JS接口只能在企业微信应用的可信域名下调用 包括子域名 且可信域
  • 深度学习环境搭建( Tensorflow & PyTorch)

    前言 硬件配置 基础软件 1 安装VC redist x64 2 安装显卡驱动并确定算力 3 确认cuda版本 4 安装CUDA 配置cudnn 5 安装Anaconda 6 安装PyCharm 深度学习框架Tensorflow安装 深度学
  • 复习之linux系统中的权限管理

    1 权限的查看及读取 1 权限的查看 ls l file 查看文件的权限 ls ld dir 查看目录权限 2 权限的读取 文件的属性叫做文件的元数据 元数据 Metadata 又称中介数据 中继数据 为描述数据的数据 data about
  • HTML爱心表白代码,亲测有效,独一无二!福利来啦!

    发福利啦 小编最近搜集了好几个表白代码 感兴趣可以点进主页看看哟 如果觉得文章不错 还请一键三联 不定时发布各种全免费的独一无二的代码 这次我们来分享跳动的爱心的代码 网上有很多 但是个人觉得我这个比较温馨一点 背景也好看
  • springboot框架介绍,让我们深入的了解

    Spring Boot是一种用于快速构建基于Spring框架的Java应用程序的开源框架 它旨在简化Spring应用程序的开发过程 通过提供一种约定优于配置的方式 让开发人员能够快速搭建起一个可独立运行的 可部署的 易于扩展的应用 Spri
  • Java的内存机制

    1 Java的内存机制 Java 把内存划分成两种 一种是栈内存 另一种是堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配 当在一段代码块定义一个变量时 Java 就在栈中为这个变量分配内存空间 当超过变量的