【JVM】内存模型

news2024/11/25 12:40:56

文章目录

  • 内存模型的基本概念
    • 案例
  • 程序计数器
    • `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.coloradmin.cn/o/2212141.html

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

相关文章

施磊C++ | 进阶学习笔记 | 3.绑定器和函数对象、lambda表达式

三、绑定器和函数对象、lambda表达式 文章目录 三、绑定器和函数对象、lambda表达式3.1模板的完全特例化和非完全(部分)特例化1.完全特例化和非完全(部分)特例化2.模板的实参推演 3.2 C STL中的绑定器bind1stbind2nd自己实现一个b…

深度学习——线性神经网络(三、线性回归的简洁实现)

目录 3.1 生成数据集3.2 读取数据集3.3 定义模型3.4 初始化模型参数3.5 定义损失函数3.6 定义优化算法3.7 训练 在上一节中,我们通过张量来自定义式地进行数据存储和线性代数运算,并通过自动微分来计算梯度。实际上,由于数据迭代器、损失函数…

基于深度学习的西红柿成熟度检测系统

简介: 基于深度学习技术的西红柿成熟度检测系统是一种利用人工智能算法对西红柿成熟程度进行自动识别和分类的智能系统。该系统通过采集西红柿的图像数据,运用深度学习模型对图像中的西红柿进行特征提取和分析,从而实现对西红柿成熟度的准确判…

【C】printf()与scanf()详介以及如何在VS中使用scanf(保姆级详细版)

printf() 基本用法 printf()的作用是将参数文本输出到屏幕,它名字里面的f 代表 format(格式化)&#xff0c;表示可以定制输出文本的格式。 1 #include <stdio.h>//standard input output标准输入输出操作 2 int main() 3{ 4 printf("Hello World"); 5 retu…

DVWA CSRF 漏洞实践报告

1. 漏洞简介 CSRF&#xff08;跨站请求伪造&#xff09;是一种攻击&#xff0c;使得攻击者能够以受害者的身份执行非预期的操作。在靶场DVWA中&#xff0c;我将尝试通过CSRF漏洞更改管理员密码。 2. 实验环境 DVWA版本&#xff1a;DVWA-old浏览器&#xff1a;火狐默认管理员账…

QtModel

QModelIndex index1 model->index(row,column,QModelIndex());QModelIndex index2 model->index(row.column,index2); QSqlQuery::size() 仅在使用了 QSqlQuery::exec() 后并且查询结果集的所有行都被读取时才有效。如果结果集很大或在使用游标的情况下&#xff0c;返回…

Linux 内核态,用户态,以及如何从内核态到用户态,交互方式有哪些

一、Linux 内核态&#xff0c;用户态 Linux 内核态&#xff0c;用户态&#xff0c;以及如何从内核态到用户态&#xff0c;我来说下我的理解 很多面试官&#xff0c;面试也是照搬照套&#xff0c;网上找的八股文面试题&#xff0c;面试的人也是背八股文&#xff0c;刚好背到了&…

全面讲解C++

数据类型 1.1 基本数据类型 1.1.1 整型&#xff08;Integer Types&#xff09; 整型用于表示整数值&#xff0c;分为以下几种类型&#xff1a; int&#xff1a;标准整数类型&#xff0c;通常为4字节&#xff08;32位&#xff09;。short&#xff1a;短整型&#xff0c;通常…

被装物联网系统|DW-S305系统是一套成熟系统

东识被装仓库管理系统&#xff08;智被装DW-S305&#xff09;作业管理软件系统包括收发管理、库房管理、库存统计、环境监测、预警管理、数据展示、系统管理等功能&#xff0c;主要功能如下&#xff1a; 收发管理&#xff1a;对库房收发物资进行管理&#xff0c;支持收发物单据…

通信工程学习:什么是TCP/IP(传输控制协议/互联网议)

TCP/IP&#xff1a;传输控制协议/互联网议 TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff0c;传输控制协议/互联网协议&#xff09;是互联网的基本协议&#xff0c;也是国际互联网络的基础。它不仅仅是一个协议&#xff0c;而是一个协议族&#…

Github 2024-10-13php开源项目日报 Top10

根据Github Trendings的统计,今日(2024-10-13统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10Vue项目2JavaScript项目1TypeScript项目1Blade项目1Coolify: 开源自助云平台 创建周期:1112 天开发语言:PHP, Blade协议类型:Apach…

算法题总结(十四)——贪心算法(上)

贪心算法 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心的套路&#xff08;什么时候用贪心&#xff09; 刷题或者面试的时候&#xff0c;手动模拟一下感觉可以局部最优推出整体最优&#xff0c;而且想不到反例&#xff0c;那么就试一试…

Vscode+Pycharm+Vue.js+WEUI+django火锅(五)Django的API

如果只是嫌弃Djanggo的前台不好&#xff0c;用vue替换&#xff0c;只要在Djanggo项目里面创建一个Vue项目文件夹&#xff0c;然后 1.修改urls.py 修改路由 2.修改settings.py中&#xff0c;增加templates内容指向vue文件夹 3.静态文件staticfile_dir中也添加vue文件夹 但因为我…

深圳大学-Java程序设计-选实验3 包及继承应用

实验目的与要求&#xff1a; 实验目的&#xff1a;熟悉面向对象编程中package,import等语句的使用。 实验要求&#xff1a; (1).编写一个计算机与软件学院类CSSE、一个研究所/中心类Institute和一个教学系类Department。CSSE类中包含有多个Institute类的实例和多个Department…

信息技术 04 WPS文字处理 图书订购单

信息技术 04 WPS文字处理 图书订购单 素材下载 信息技术 04 WPS文字处理 图书订购单链接&#xff1a;https://pan.baidu.com/s/1_S9HMfmiC6JJcjk4nO-tKg?pwdi304 提取码&#xff1a;i304 成品样图 题目 任务实现具体要求如下&#xff1a; ① 根据设计好的表格的结构&#…

基于 PyQt5 和 Matplotlib 的医学图像处理应用开发

1. 引言 在医学领域&#xff0c;图像处理是一项非常重要的技术&#xff0c;特别是在医学成像&#xff08;如MRI、CT扫描等&#xff09;的数据处理上&#xff0c;可以帮助医生更加准确地进行诊断。本项目基于 Python 的 PyQt5 图形用户界面框架与 Matplotlib 数据可视化库&…

Variational Auto-Encoder(VAE)缺少数学推导未完结版

VAE是Diffusion的基础&#xff0c;在其中将输入的图片数据编码到潜在空间后再解码出来。 略显复杂&#xff0c;博主结合李宏毅视频、网上一些讲解以及自己的理解将其总结如下&#xff1a; 一、什么是VAE VAE&#xff08;变量自编码器&#xff09;最早在以上两篇文章被提出。 …

yakit使用教程(四,信息收集)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 前言&#xff1a;yakit下载安装教程。 一&#xff0c;基础爬虫。 在新建项目或新建临时项目后&#xff0c;点击安全工具&#xff0c;点击基础爬虫。 此工具并不是为了爬取网站上的一…

【零散技术】MAC 安装多版本node

时间是我们最宝贵的财富,珍惜手上的每个时分 不同前端项目运行的node版本不一致&#xff0c;会导致无法运行&#xff0c;就像Odoo也需要依据版本使用对应的python环境。python 可以用 conda随时切换版本&#xff0c;那么Node可以吗&#xff1f;答案是肯定的。 1、安装 n&#x…

k8s-资源管理、实战入门

资源管理 一、资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 &#xff08;1&#xff09;kubernetes的本质上就是一个集群系统&#xff0c;用户可以在集群中部署各种服务&#xff0c;所谓的部署服务&…