Java内存详解

内存区域、内存模型

  • 内存区域:即运行时数据区域,指JVM对于不同类型数据在内存中的存储方式
  • 内存模型(JMM:Java Memory Model):定义了线程与主内存之间的抽象关系,即JVM在内存中的工作方式,即JVM使用内存区域中的数据的方式

JDK8之后的内存区域:

* Native Method Stacks(本地方法栈)
* Program Counter Register(程序计数器)
* Java Virtual Machine Stacks(JVM Stacks,即虚拟机栈)* Stack Frame(栈帧)* 局部变量表* 操作栈* 动态连接* 方法返回地址* Stack Frame(栈帧)* 局部变量表* 操作栈* 动态连接* 方法返回地址
* Heap(堆区)* Young区(新生代)* Eden* S0* S1* Old区(老年代)
* Method Area(方法区)* Runtime Constant Pool(运行时常量池)* 方法元信息* klass类元信息
* CodeCache(JIT编译产物) 

Program Counter Register (程序计数器)

  • 作用:当前线程所执行的字节码的行号指示器,当多线程切换时,使线程恢复后找到正确的执行位置
  • 特点:
    • 内存占用少
    • 线程私有
    • 当前线程执行Java方法,计数器保存虚拟机中字节码指令地址;执行Native方法,记录null
    • 唯一一个在JVM规范中没有规定OutOfMemoryError的区域

JVM Stacks

  • 概念:
    • 活动线程:当前正在执行的线程
    • 当前帧:正在执行的方法对应的栈帧,由于只有栈顶帧有效,所以当前帧也是栈顶帧
    • 当前方法:正在执行的方法
  • 简介:描述了Java方法执行的内存模型,每个方法在执行时都会创建一个栈帧(Stack Frame:栈中的一个元素,方法运行时的基础数据结构),存储局部变量表,操作数栈、动态连接、方法出口等。每一个方法从调用到执行完的过程,对应一个栈帧入栈出栈过程
  • 作用:保存Java方法执行的时候需要的各种数据、参数
  • 特点:
    • 线程私有
    • 生命周期与线程相同
    • 执行引擎运行时,所有指令都只能对当前帧操作
    • 一个方法对应一个栈帧
  • 组成:
    • Stack Frame(栈帧):
      • 介绍:一个栈帧对应一个方法执行需要的数据
      • JVM规定的与栈帧相关异常:
        • 线程请求的栈深度大于JVM允许的深度,抛出StackOverflowError
        • 对于当前大多数可以拓展的JVM栈,在拓展时申请不到足够内存,抛出OutOfMemoryError
      • 组成:
        • 局部变量表
          • 作用:存放方法参数和局部变量,字节码指令中的STORE指令就是将操作栈中计算完成局部变量写到当前帧的局部变量表中
          • 特点:
            • 必须显示初始化,才能使用
            • 如果是非静态方法,会在index[0]位置存储方法所属对象的实例引用,占用4字节,后面存储方法参数和局部变量
        • 操作栈
          • 作用:用于方法执行过程中信息的存取
          • 简介:JVM的执行引擎是基于栈的执行引擎,其中的栈即操作栈,方法执行时,使用操作栈进行存取信息
          • 关联:
            • 字节码指令集即基于栈类型,栈深度保存在方法元信息的栈属性中
            • 例:
              • ++i:总体思路是按顺序执行,先将局部变量表中的i执行加1操作(load memory&add&store memory),然后放到操作栈中(load memory),此时从操作栈栈顶取出的i就是加1之后的
              • i++:按照按顺序执行的思路,先将i放到操作栈中(load memory),然后执行加1的操作(add memory),加1之后的值更新到局部变量表中(store memory),此时从栈顶读取到的i未加1,所以如果多线程操作i的时候,可能从局部变量表读到的i比预期的小
          • 特点:
            • 初始状态为空桶式结构栈
        • 动态连接
          • 介绍:每个栈帧中包含一个在常量池中对当前方法的引用,目的是为了支持方法调用过程的动态连接
        • 方法返回地址:
          • 方法执行退出情况:
            • 正常退出,遇到返回字节码指令,比如return、ireturn、areturn
            • 异常退出
          • 介绍:即方法调用完成返回的位置,方法调用完成后会弹出当前栈帧
          • 退出后行为:
            • 返回值压入上层调用栈帧
            • 异常抛给能处理的栈帧
            • 程序计数器指向方法调用后的下一条指令

Native Method Stacks(本地方法栈)

  • 介绍:与JVM Stacks类似,但保存的是Native方法对应的栈帧
  • 特点:
    • 也会抛出StackOverFlowError和OutOfMemoryError
    • 线程调用本地方法时,不受JVM约束
    • 本地方法通过JNI(Java Native Interface)来访问JVM的数据,可以调用寄存器,具有JVM相同的能力、权限
    • 大量本地方法运行时,会削弱JVM对系统控制力,本地方法出错信息比较黑盒
    • 本地方法栈会在内存不足时抛出NativeHeapOutOfMemory

Heap(堆)

  • 介绍:存放对象实例,几乎所有的对象实例都在这里分配内存
  • 特点:
    • 对大多数应用来说,Heap是JVM管理内存中最大的一块
    • 被所有线程共享
    • 虚拟机启动时创建
    • GC管理的主要区域,有时候也成Heap为GC Heap
    • 内部可能包含多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)
    • 可以由物理上不连续的内存空间组成,只要逻辑上连续即可
    • 当堆中无内存完成实例分配,并且无法拓展时,会抛出OutOfMemoryError
  • 按照GC中的分代回收算法分类:
    • 新生代
      • Eden
      • S0
      • S1
    • 老年代

Metaspace(元数据区)

  • 组成:
    • Method Area(方法区)
      • 特点:
        • 线程共享
        • 存储被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
        • JVM对该区域限制非常松,可选择不实现垃圾回收
        • 垃圾回收在该区域出现少,主要是回收运行时常量池和类元信息
        • 当方法区无法满足内存分配需求时,抛出OutOfMemoryError
    • Runtime Constant Pool(运行时常量池)
      • 作用:
        • 用于存放编译器生成的各种字面量、符号引用、翻译出来的直接引用
      • 特点:
        • 具备动态性,非编译期也可以产生常量,运行期间可以将常量放入池中,例如String的intern() 方法
        • 当申请不到新内存时,抛出OutOfMemoryError

直接内存

  • 作用:
    • 用于避免Java堆与native对来回复制数据,提高某些场景的性能
  • 特点:
    • 非虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域
    • 基于通道(Channel)与缓冲区(Buffer)的I/O方式,可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用来操作
    • 动态拓展时申请不到足够内存会抛出OutOfMemoryError

Java Memory Model(java内存模型)

  • 作用:
    • 控制线程之间的通信,决定一个线程对共享变量的写入何时对另一个线程可见
    • 定义程序中各个变量的访问规则
  • 特点:
    • 共享内存的并发模型,线程之间通过读写共享变量(堆内存中的实例域、静态域、数组元素)来完成隐式通信
    • 所有变量都存储在主内存中,每条线程有自己的私有内存,也叫工作内存,线程对变量的操作必须在工作内存中进行,不能直接操作主内存中的变量,工作内存中存储了变量副本
    • 属于语言级的内存模型,在不同的编译器、处理器上,通过禁止特定类型的编译器重排序和处理器重排序(指令级并行重排序、内存系统重排序),确保为程序员提供一致的内存可见性

重排序

  • 作用:
    • 编译器和处理器为了提高性能,会对指令重排序
  • 分类:
    • 编译器优化的重排序:
      • 编译器在不改变程序语义的情况下,可以重排语句执行顺序
    • 指令级并行的重排序:
      • 现代处理器提供了指令级并行技术来将多条指令并行执行,如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
    • 内存系统的重排序:
      • 由于处理器使用了缓存和读写缓冲区,使加载和存储操作看上去是在乱序执行
  • 从Java源代码到执行指令序列:
    • 源代码 > 编译器优化重排序 > 指令级重排序 > 内存系统重排序 > 最终执行的指令序列
  • Java进制处理器重排序方式:
    • 生成指令序列的内存屏障,即重排序时不能把内存屏障指令重排到之前来实现的

happens-before

  • 作用:
    • 描述操作之间的内存可见性(可见性:指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的)
  • 特点:
    • JDK5出现
    • 如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在 happens-before 关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间
  • 重要的 happens-before 规则如下:
    • 程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。
    • 监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。
    • volatile 变量规则:对一个 volatile 域的写,happens- before 于任意后续对这个 volatile 域的读。
    • 传递性:如果 A happens- before B,且 B happens- before C,那么 A happens- before C。

volatile

  • 作用:
    • 保持变量的修改在多个线程间是同步的
  • 特点:
    • 保证变量对所有线程都是可见的
    • volatile变量在并发情况下由于Java的非原子化操作导致线程不安全,synchronized由于统一时间内只能由一个线程操作,所以是线程安全的
    • 禁止指令重排序优化

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

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

相关文章

微信小程序如何使用weui组件库?

一、方法一:通过npm安装 通过npm构建方式引入weui组件库 (找到.eslintrc.js 右键,在内件终端打开)打开命令提示符后,输入 (1)npm init -y来快速生成一个默认的package.json文件 (…

鸿蒙 装饰器@builder 使用中的问题 以及解决方案

builder装饰器 一 介绍Builder装饰器:自定义构建函数二 问题点三 解决方法四 仓库地址 一 介绍Builder装饰器:自定义构建函数 用于填充UI组件 开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。 根据场景分类 组件内自定义构…

设计非递归算法,编程:在二叉排序树中,打印关键码a, b的公共祖先。注:例,若a是b的祖先,则a不算作公共祖先。反之亦然。

二叉排序树&#xff1a; 代码&#xff1a; #include <iostream> using namespace std;// 定义二叉树节点结构 typedef struct BTNode {char show;struct BTNode* left;struct BTNode* right; } BTNode;// 非递归插入节点的函数 BTNode* insertNode(BTNode* root, char k…

Leetcode - 周赛397

目录 一&#xff0c;3146. 两个字符串的排列差 二&#xff0c;3147. 从魔法师身上吸取的最大能量 三&#xff0c;3148. 矩阵中的最大得分 四&#xff0c;3149. 找出分数最低的排列 一&#xff0c;3146. 两个字符串的排列差 本题就是求同一个字符在两个字符串中的下标之差的…

QCustomPlot的了解

&#xff08;一&#xff09;QCustomPlot常见属性设置、多曲线绘制、动态曲线绘制、生成游标、矩形放大等功能实现-CSDN博客 关键代码&#xff1a; QT core gui printsupport 使用上面文章中的代码跑起来的程序效果图&#xff1a; 我的学习过程&#xff1a; 最开始初…

家用充电桩远程监控安全管理系统解决方案

家用充电桩远程监控安全管理系统解决方案 在当今电动汽车日益普及的背景下&#xff0c;家用充电桩的安全管理成为了广大车主关注的重点问题。为了实现对充电桩的高效、精准、远程监控&#xff0c;一套完善的家用充电桩远程监控安全管理系统解决方案应运而生。本方案旨在通过先…

如何去除字符串两侧的空白字符?

TRIM函数会去掉字符串左侧和右侧的空格&#xff0c;语法是&#xff1a;TRIM(字符串) excel中&#xff0c;TRIM函数能去掉字符串左侧和右侧的空格&#xff0c;它的ASCII码是32。 以下设定一个字符串组合&#xff0c;它的第一个字符中空格&#xff0c;最后一个字符是换行符 &q…

Python专题:十七、做个小游戏

终端小游戏 1、根据题库内容出单选题 2、提示作答&#xff0c;并给结果 思路 列表 保存题目 字典 保存题干&#xff0c;选项和答案 遍历 题目列表用于展示 input函数 等待用户输入 判断输入&#xff0c;并继续提示 计算正确率并打印 题库…

oracle不得不知道的sql

一、oracle 查询语句 1.translate select translate(abc你好cdefgdc,abcdefg,1234567)from dual; select translate(abc你好cdefgdc,abcdefg,)from dual;--如果替换字符整个为空字符 &#xff0c;则直接返回null select translate(abc你好cdefgdc,abcdefg,122)from dual; sel…

【Linux进程通信 —— 管道】

Linux进程通信 —— 管道 进程间通信介绍进程间通信的概念进程间通信的目的进程间通信的本质进程间通信的分类 管道什么是管道匿名管道匿名管道的原理pipe用fork来共享管道原理站在文件描述符角度-深度理解管道站在内核角度-管道本质管道读写规则管道的特点管道的四种特殊情况管…

2024软件测试必问的常见面试题1000问!

01、您所熟悉的测试用例设计方法都有哪些&#xff1f;请分别以具体的例子来说明这些方法在测试用例设计工作中的应用。 答&#xff1a;有黑盒和白盒两种测试种类&#xff0c;黑盒有等价类划分法&#xff0c;边界分析法&#xff0c;因果图法和错误猜测法。白盒有逻辑覆盖法&…

三子棋游戏

1、实现三子棋 test.c //测试游戏的逻辑 game.c //游戏代码的实现 game.h //游戏代码的声明&#xff08;函数声明&#xff0c;符号定义&#xff09; 1、 在主函数里实现&#xff0c;首先有个界面&#xff0c;让玩家选择是否玩游戏。上来就先打印菜单&#xff0c;用do ... …

优秀测试的核心能力!2招高效定位分析BUG!

之所以写这一篇文章&#xff0c;是突然想起来曾经在测试过程中被开发嘲讽过&#xff0c;事情是这样的&#xff0c;当时发现了一个疑似前端的Bug就草草提交到了禅道&#xff0c;结果刚来的女前端看到了就有点生气地问我为啥不查清到底是前后端问题就直接派给她前端了&#xff0c…

【python量化交易】—— Alpha选股策略 - Qteasy自定义交易策略【附源码】

使用qteasy创建并回测Alpha选股交易策略 使用qteasy创建并回测Alpha选股交易策略策略思想第一种自定义策略设置方法&#xff0c;使用持仓数据和选股数据直接生成比例交易信号PS信号&#xff1a;第二种自定义策略设置方法&#xff0c;使用PT交易信号设置持仓目标&#xff1a;第三…

【数组中重复的数据】leetcode,python

和上题一样&#xff0c;【找到所有数组中消失的数字】 换个判断条件就行 class Solution:def findDuplicates(self, nums: List[int]) -> List[int]:nlen(nums)for i in nums:x(i-1)%nnums[x]n#只需要替换条件即可return [i1 for i,num in enumerate(nums) if num>(2*n)…

第十四节 huggingface的trainner的_inner_training_loop函数源码解读

文章目录 前言一、self.get_train_dataloader()函数1、self.get_train_dataloader()函数完整源码2、dataset与dataloadera、dataset与dataloader来源b、dataset与dataloader处理c、self._get_collator_with_removed_columns()函数获得collate_fn3、self._get_train_sampler()采…

grep命令总结

grep命令可以是根据特定条件过滤文本内容。 查看含义指定字符的行 这里就是过滤含有root的行 [rootlu-k8s-master133 ~]# grep root /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin查看开头含有指定字符的行 这里就是使用^r 代…

算法随想录第八天打卡|344.反转字符串,541. 反转字符串II, 卡码网:54.替换数字, 151.翻转字符串里的单词,卡码网:55.右旋转字符串

344.反转字符串 建议&#xff1a; 本题是字符串基础题目&#xff0c;就是考察 reverse 函数的实现&#xff0c;同时也明确一下 平时刷题什么时候用 库函数&#xff0c;什么时候 不用库函数 题目链接/文章讲解/视频讲解&#xff1a;代码随想录 Python class Solution:def reve…

海外云手机的运作原理和适用场景

海外云手机是一种基于云计算技术的虚拟手机服务&#xff0c;通过将手机操作系统和应用程序托管在远程服务器上&#xff0c;实现用户可以通过互联网连接来使用和管理手机功能&#xff0c;而无需实际拥有物理手机。以下是有关海外云手机的相关信息&#xff1a; 海外云手机的运作原…

202212青少年软件编程(Python)等级考试试卷(二级)

第 1 题 【单选题】 运行下列程序&#xff0c; 最终输出的结果是&#xff1f; &#xff08; &#xff09; info {1:小明, 2:小黄,3:小兰}info[4] 小红info[2] 小白print(info)A :{1: ’ 小明’ , 2: ’ 小白’ , 3: ’ 小红’ , 4: ’ 小兰’ } B :{1: ’ 小明’ , 2: ’…