【JVM】内存模型

文章目录

  • 内存模型的基本概念
    • 案例
  • 程序计数器
    • `Java`虚拟机栈
      • 局部变量表
        • 栈帧中局部变量表的实际状态
        • 栈帧中存放的数据有哪些
      • 操作数栈
      • 帧数据
    • 本地方法栈
    • 堆空间是如何进行管理的?
  • 方法区
    • 静态变量存储
  • 直接内存
    • 直接内存的作用

内存模型的基本概念

在前面的学习中,我们知道了字节码文件(.class)会通过类加载器加载JVM虚拟机中,接下来JVM虚拟机就会执行其中的字节码指令.我们把JVM虚拟机被分配的内存叫做运行时数据区域
内存模型就是指运行时数据区域中被划分的不同区域.
JDK6版本:
在这里插入图片描述字符串常量池存放在方法区中,方法区存放在堆中;
JDK1.7版本:
在这里插入图片描述

  • 方法区脱离堆,单独占用一部分内存

  • 字符串常量池依旧存储在堆中
    JDK1.8版本:
    在这里插入图片描述

  • 方法区发生移动,从JVM虚拟机内存中,移动到本地内存中

Java虚拟机(JVM)的内存模型是Java程序运行时内存管理的基础。它定义了Java程序如何在内存中分配、使用和回收资源

案例

class Person{int id;String name;public Person(int id,String name){this.id=id;this.name=name;}
}
public class JvmTest {public void func1(int a){int b=10;Person p=new Person(1,"张三");a=11;}public static void main(String[] args) {int a=10;new JvmTest().func1(a);System.out.println(a);}
}

在这里插入图片描述

程序计数器

  1. 控制程序解释执行指令的顺序.在代码执行过程中,程序计数器会记录下一行字节码指令的地址.执行完当前指令之后,虚拟机的执行引擎根据程序计数器执行下一行指令.程序计数器可以控制程序指令的进行,实现分治,跳转或者异常等等逻辑
  2. 保证在多线程的情况下线程之间的切换.JVM虚拟机需要通过程序计数器记录CPU切换前解释执行到哪一行指令并继续解释运行

程序计数器会不会发生内存溢出?
内存溢出:程序在使用某一块内存区域时,存放的数据需要占用的内存大小超过了虚拟机能够提供的内存上限
程序计数器不会发生内存溢出的情况.原因:每个程序计数器只会存储一个固定长度的内存地址,也就是字节码指令的内存地址.

Java虚拟机栈

保存在java中实现的方法
采用的数据结构来管理方法调用中的基本数据,先进后出,每一个方法的调用使用一个栈帧来保存.
Java虚拟机栈随着线程的创建而创建,随着线程的结束而销毁
在每一个栈帧中,存放的内容有:局部变量表,操作数栈,帧数据
在这里插入图片描述

局部变量表

在方法执行过程中存放所有的局部变量,编译成字节码文件时,就可以确定局部变量表的内容
在这里插入图片描述

栈帧中局部变量表的实际状态

栈帧中的局部变量表是一个数组,数组中的每一个位置称之为,longdouble类型占用两个槽,其他类型占用一个槽.
在这里插入图片描述

栈帧中存放的数据有哪些
  • 实例方法中的序号为0的位置存放的是this,指的是当前调用方法的实例对象,运行时会在内存中存放实例对象的地址
  • 方法参数也会保存在局部变量表中,其顺序与方法中参数定义的顺序一致

局部变量表保存的内容有:

  • 实例方法的this对象
  • 方法的参数
  • 方法体声明的局部变量

为了节省空间,局部变量表中的槽是可以复用的,一旦某个局部变量不再生效,当前槽就可以再次被使用

操作数栈

操作数栈是栈帧中虚拟机执行指令过程中用来存放临时数据的一块区域

  • 操作数栈是栈帧中虚拟机在执行指令的过程中用来存放中间数据的一块区域.他是一种栈式的数据结构,如果一条指令将一个值压入操作数栈,则后面的指令可以弹出并使用该值.

比如:在字节码指令执行的过程中,会产生一些临时数据,这些临时数据会先存放到操作数栈中,然后再通过下一条指令放入到局部变量表中

  • 在编译期就可以确定操作数栈的最大深度,从而执行时正确的分配内存大小

帧数据

(这个并不是由虚拟机设定标准)
帧数据主要包含动态链接,方法出口,异常表引用

  • 动态链接:当前类的字节码指令引用了其他类的属性或者方法时,需要将符号引用(编号)转换成对应的运行时常量池中的内存地址.动态链接就保存了编号到运行时常量池的内存地址的映射关系.
    在这里插入图片描述

  • 方法出口:方法在正确或者异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址.所以在当前栈帧中,需要存储此方法出口的地址.

  • 异常表:存放的是代码中异常的处理信息,包含了异常捕获的生效范围以及异常发生后跳转到的字节码指令位置.

Java虚拟机栈是否会出现栈内存溢出?

  • Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大容量,就会出现栈溢出(虚拟机为每一个线程分配的栈的大小是有限的)
  • Java虚拟机栈内存溢出时会出现StackOverflowError的错误

本地方法栈

保存的是在java中实现的使用native修饰的,实际是由C++编写的本地方法

  • Java虚拟机栈存储了Java方法调用时的栈帧,而本地方法栈存储的是native本地方法的栈帧.
  • HotSpot虚拟机中,Java虚拟机栈和本地方法栈实现上使用了同一个栈空间.本地方法栈在栈内存上生成一个栈帧,临时保存方法的参数同时方便出现异常时也把本地方法的栈信息打印出来.
    在这里插入图片描述

一般Java程序中堆内存是空间最大的一块内存区域.创建出来的对象都存在于堆上
Java 堆是所有线程共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都存放在这里,是垃圾收集器管理的主要区域
栈上的局部变量表中,可以存放堆上对象的引用.静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间的共享.
在这里插入图片描述

堆内存是否会出现溢出?
堆内存大小是有上限的,当对象一直向堆中放入对象达到上限之后,就会抛出OutOfMemory错误

堆空间是如何进行管理的?

堆空间有三个需要关注的值:uesd,total,max

  • used指的是当前已经使用的堆内存;
  • totaljava虚拟机已经分配可用堆内存;
  • maxjava虚拟机可以分配的最大堆的内存
    在这里插入图片描述

随着堆中对象增多,当total可以使用的内存即将不足的时候,虚拟机会继续分配内存给堆,扩展total的大小

  • 如果堆内存不足,java虚拟机就会不断地分配内存,total值会变大.
  • 是不是当used=total=max,就会导致内存溢出?
    答案:不一定

在实际应用中一般都需要设置totalmax的值

  • 要修改堆的大小,可以使用虚拟机参数-Xmx(max最大值)和-Xms(初始的total)
    • 语法:-Xmx值,-Xms
    • 单位:字节(默认,必须是1024倍数),K或者k(KB),m或者M(MB),g或者G(GB)
    • 限制:Xmx必须大于2MB,Xms必须大于1MB

Java服务端程序开发的时候,建议将-Xmx-Xms设置为相同的值(total=max),这样在程序启动之后可使用的总内存就是最大内存,而无需向Java虚拟机再次申请,减少了申请并分配内存时间上的开销,同时也不会出现内存过剩之后堆收缩的情况

方法区

方法区是存放每个类基础信息的位置,线程共享,主要包含三部分内容:

  • 类的元信息:每个类的基本信息
    一般称之为InstanceKlass对象.在类加载阶段完成
    在这里插入图片描述
  • 运行时常量池
    • 常量池中存放的是字节码中的常量池内容
    • 字节码文件中通过编号查表的方式找到常量,这种常量池称之为静态常量池
    • 常量池加载到内存中之后,可以通过内存地址快速的定位到常量池中的内容,这种常量池称之为运行时常量池.
      在这里插入图片描述
    • 字符串常量池:保存了字符串常量
      字符串常量池存储在代码中定义的常量字符串内容.比如:"123",这个123就会被放入字符串常量池
      在这里插入图片描述
      这里我们再来举个例子加深印象:
      举例1:
public class StringTest {public static void main(String[] args) {String a="1";String b="2";String c="12";String d=a+b;System.out.println(c==d);}
}

这里的运行结果就代表了我们的d是存放在字符创常量池中还是堆内存中.
运行结果false,原因如下:
在这里插入图片描述
举例2:

public class StringTest {public static void main(String[] args) {String a="1";String b="2";String c="12";String d="1"+"2";System.out.println(c==d);}
}

运行结果是:true,为什么?
我们来观察一下此时的字节码指令状态:
在这里插入图片描述
所以,此处d存放在常量池中的原因是:这里并没有使用StringBuilder对象来进行字符串的相加,而是直接使用的ldc字节码指令进行的,没有使用对象,所以就不需要存放在

静态变量存储

  • JDK7之前的版本中,静态变量是存放在方法区中的,也就是永久代
  • JDK7及其之后的版本中,静态变量时存放在堆中的Class对象中,脱离了永久代

直接内存

首先我们要确定的是,直接内存并不属于Java运行时的内存区域.
JDK1.4中引入了NIO机制,使用了直接内存,主要为了解决以下两个问题:

  • Java堆中的对象如果不再使用要回收,回收时会影响对象的创建和使用(可能会出现卡顿的现象)
  • IO操作比如读文件,需要先把文件读入直接内存中,再把数据复制到Java堆中.
    现在放入直接放入到直接内存中即可,同时在Java堆上维护直接内存的引用,减少了数据复制的开销.写文件也是这种思路.
    在这里插入图片描述

直接内存的作用

  • 提高读写文件的性能
  • 避免垃圾回收机制影响对象的创建和使用
  • 在`JDK1.78即之后存放方法区

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

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

相关文章

Java 8 Stream API:从基础到高级,掌握流处理的艺术

一、Stream(流)基本介绍 Java 8 API 添加了一个新的抽象称为Stream(流),可以让你以一种声明的方式处理数据,这种风格将要处理的元素集合看做一种流,元素流在管道中传输,并在管道中间…

云黑系统全解无后门 +搭建教程

这套系统呢是玖逸之前南逸写的一套云黑系统,功能带有卡密生成和添加黑名单等,源码放在我的网盘里已经两年之久,由于玖逸现在已经跑路了所以现在发出来分享给大家,需要的可以自己拿去而开,反正功能也不是很多具体的自己…

电脑视频剪辑大比拼,谁更胜一筹?

随着短视频的火爆,越来越多的人开始尝试自己动手制作视频,无论是记录生活点滴还是创作个性短片,一款好用的视频剪辑软件是必不可少的。今天,我们就从短视频运营的角度,来聊聊几款热门的电脑视频剪辑软件,看…

docker配置加速器

阿里云 控制台》容器镜像服务》镜像工具》镜像加速器 复制地址:https://ywtoq7bz.mirror.aliyuncs.com 到:etc/docker下:vi daemon.json 格式: { "registry-mirrors": ["加速器地址"] } 注&#xff1…

JavaScript:闭包、防抖与节流

一,闭包 1,什么是闭包 闭包是指一个函数和其周围的词法环境(lexical environment)的组合。 换句话说,闭包允许一个函数访问并操作函数外部的变量。 闭包的核心特性: 函数内部可以访问外部函数的变量即使外部函数已经返回,内部…

一款新开源跨平台的.NET Word(docx)模版导出引擎,完美支持Linux和Mac操作系统(附源码)

前言 在数字化办公日益盛行的今天,文档处理成为了我们日常工作不可或缺的一部分。然而,许多传统的文档处理工具都依赖于特定的操作系统和复杂的组件安装,这无疑给跨平台办公带来了诸多不便。为了解决这一问题,我们找到了一个新的…

【MR开发】在Pico设备上接入MRTK3(一)——在Unity工程中导入MRTK3依赖

写在前面的话 在Pico上接入MRTK3,目前已有大佬开源。 https://github.com/Phantomxm2021/PicoMRTK3 也有值得推荐的文章。 MRTK3在PICO4上的使用小结 但由于在MacOS上使用MRTK3,无法通过Mixed Reality Feature Tool工具管理MRTK3安装包。 故记录一下…

◇【论文_20151120_20160405v3】Dueling Network 决斗〔Google DeepMind〕

整理代码:Dueling_DQN__Pendulum_v1.ipynb https://arxiv.org/abs/1511.06581 Dueling Network Architectures for Deep Reinforcement Learning 文章目录 摘要1. 引言1.1. 相关工作 2. 背景2.1. Deep Q-networks 【DQN】2.2. Double Deep Q-networks 【DDQN】2.3…

OpenCV高级图形用户界面(13)选择图像中的一个矩形区域的函数selectROI()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 允许用户在给定的图像上选择一个感兴趣区域(ROI)。 该功能创建一个窗口,并允许用户使用鼠标来选择一个 ROI。…

其他css的用途

1.animation-fill-mode: backwards; //避免了在动画开始前元素的突然显现,动画必要。 2.用rem响应式字体大小,可以在html样式定义font-size?(例10px,62.5%(100%是16px))。然后样式就可以用rem代替px。 3.color: transparent;: 这行代码将文…

计算生物学与生物信息学漫谈-2-测序深度/读长质量和Fasta处理

上一篇文章中我们介绍了测序技术的由来与发展,那么在介绍第三代测序的时候,我们提到了关于测序深度和读长的问题,那么本篇文章就详解介绍一下。 计算生物学与生物信息学漫谈-1-测序一路走来-CSDN博客 目录 1.测序深度SEQUENCING DEPTH &…

《AI生成式工具使用》之:自助生成视频

目录 背景说明及目标: 实现过程: 1、有问题找度娘 2、利用剪映AI生成视频具体步骤 剪映AI感受 3、利用万彩AI生成视频具体步骤 万彩AI感受 4、利用腾讯云剪生成视频具体步骤 腾讯云剪感受 最终结论: 关注我,躺不平就一起…

【部署篇】RabbitMq-02单机模式部署

RabbitMQ和Erlang/OTP兼容性矩阵 下表提供了当前支持的RabbitMQ版本系列的Erlang兼容性矩阵。更多RabbitMQ版本,请参阅官网的系列兼容性列表。官网地址:https://www.rabbitmq.com/docs/which-erlang RabbitMQ版本最小支持版本最大支持版本备注 4.0.24.…

Axure重要元件三——中继器添加数据

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 本节课:中继器添加数据 课程内容:添加数据项、自动添加序号、自动添加数据汇总 应用场景:表单数据的添加 案例展示: 步骤…

经验是最坏的老师

奥斯卡.王尔德说过:经验是最坏的老师。他经常先考试,然后再给出指导。 这让我想起了另外一句话:愚笨的人,往往都在犯同样的错误;普通的人,从自己的错误中学习;聪明人从别人的错误中学习。 如果…

Linux 防火墙的开启、关闭、禁用命令

Linux 防火墙的开启、关闭、禁用命令 文章目录 Linux 防火墙的开启、关闭、禁用命令1.设置开机启用防火墙2.设置开机禁用防火墙3.启动防火墙4.关闭防火墙5.检查防火墙状态 1.设置开机启用防火墙 systemctl enable firewalld.service2.设置开机禁用防火墙 systemctl disable f…

006、链表分割

0、题目描述 链表分割 这道题的思路,遍历原链表,小于x的放到一个链表里,大于x的放到另一个链表里。然后把两个链表接起来。 建立的两个新链表都是有哨兵位的,也就是有头结点,排序结束后要free两个头结点。 1、法1 还…

CSS3 提示框带边角popover

CSS3 提示框带边角popover。因为需要绝对定位子元素&#xff08;这里就是伪元素&#xff09;&#xff0c;所以需要将其设置为相对对位 <!DOCTYPE html> <html> <head> <title>test1.html</title> <meta name"keywords" con…

格点拉格朗日插值与PME算法

技术背景 在前面的一篇博客中&#xff0c;我们介绍了拉格朗日插值法的基本由来和表示形式。这里我们要介绍一种拉格朗日插值法的应用场景&#xff1a;格点拉格朗日插值法。这种场景的优势在于&#xff0c;如果我们要对整个实数空间进行求和或者积分&#xff0c;计算量是随着变量…

JDK中socket源码解析

目录 1、Java.net包 1. Socket通信相关类 2. URL和URI处理类 3. 网络地址和主机名解析类 4. 代理和认证相关类 5. 网络缓存和Cookie管理类 6. 其他网络相关工具类 2、什么是socket&#xff1f; 3、JDK中socket核心Api 4、核心源码 1、核心方法 2、本地方法 3、lin…