我看Java虚拟机(2)---Java虚拟机内存区域详解

2023-11-16

虚拟机内存区域的组成

直接上图:
这里写图片描述

  • 程序计数器:对于Java方法,用来选取下一条要执行的字节码;对于本地方法,值为空。线程独有
  • 虚拟机栈:执行Java方法,每一层都是一个栈帧,栈帧包括局部变量表、操作数栈、动态链接和方法出口等信息。线程独有
  • 本地方法栈:执行Native方法,sun HotSpot将其与虚拟机栈合二为一。
  • :存放对象实例。堆分为新生代和老生代,新生代分为Eden区和两个Survivor区,默认Eden和Survivor(一个Survivor)之比为8:1。所有线程共享
  • 方法区:HotShot将其实现为永生代。虚拟机读入(javac编译器生成)class文件,将会存储信息到该部分,则该部分会存储虚拟机加载的类信息,常量,静态变量即时编译器编译后的代码。该部分还有一个重要的组成部分——常量池。所有线程共享
  • 直接内存:严格来说这部分并不属于Java虚拟机的内存区域,不过Java 在JDK1.4中新加入了NIO类,引入了基于通道和缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后在Java堆中生成一个该内存地址的引用,使用该引用来操作堆外内存中的对象。

内存分配和垃圾收集

  • 程序计数器不存在内存分配的问题。
  • 虚拟机栈和本地方发栈是在运行时,给将要运行的方法分配内存。
  • 方法区在类加载的时候分配内存。
    以下都是主要研究堆内存的分配和垃圾回收

内存分配

堆中区域图:

这里写图片描述
主要有以下几点:
对象优先在Eden区分配:当Eden区内存不足时,将发起一次Minor GC(Garbage Collection),需要将Eden区和Survivor A(笔者自行编的号,另一个则编号Survivor B)区中,仍旧存活的数据全部复制到Survivor B区中;当下一次GC时,则Survivor A和Survivor B互换位置,即Survivor B+Eden —–复制到—–》Survivor A,如此循环,循环,循环。。。直到Survivor 再也不能容纳Eden+Survivor的时候,老生代就不能再闲着了,就会选择一些数据放置到老生代了。那么问题来了,要选择哪些数据去老生代呢?即选择的标准是什么,接着往下看。
老生代:能进入老生代的数据分两种:“先天条件好的”大对象和“后天足够努力的“顽强者。先天条件好的大对象享受特权,可直接分配内存到老生代,主要是考虑到当发生Minor GC(当作城管)时,若管理的区域全是有背景的大对象,清理起来特别不方便,影响装X;那么问题又来了:多大才是大?虚拟机提供了-XX:PretenureSizeThreshold参数(只对Serial和ParNew两个收集器有效,垃圾收集会讲到)来设置。
小对象就没了这种顾虑,让你去Survivor A绝不会去Survivor B,正所谓大浪淘沙,为了能挑选出顽强的对象,有两种方式来判定:

  1. 计数器:给每一个新生代的对象配一个计数器,当发生一次Minor GC,对象移动一次,计数器+1,直到达到设定的值(默认15,可通过–XX:MaxTenuringThreshhold设置),就可以进入老生代。
  2. 动态判定:当新生代相同年龄的对象的大小之和大于Survivor(一个)的一半,则将该年龄的对象和比他们老的对象全部进入老生代。

当新生代对象需要进入老生代时,老生代也不是无限大的,所以保不齐需要复制进老生代的对象,其大小会超出老生代的最大容量,这时候,就会进行分配担保。简单说,虚拟机会根据以往,每次晋升到老生代所需分配内存的平均值,比较老生代剩余空间,如果大于剩余(即剩余空间不足),则进行一次Full GC(清理老生代);如果小于剩余,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,则进行Minor GC,否则Full GC。

垃圾收集

三个知识点:

  1. 判断对象死亡
  2. 垃圾收集算法
  3. 垃圾收集器
    判断对象死亡
    两种算法:
    • 计数器:当对象有一条引用时,其引用计数器加一,当计数器为0时,可判断其死亡。缺陷:当堆中对象互相引用时,即使外部没有了指向该对象的引用,他们计数器也不为0,不能被回收,如图:
      这里写图片描述
    • 根搜索:每个节点都是一个对象,有一个根节点,当有节点到根节点不可达时,即可判断该对象死亡。Java和C#都使用该算法。如图4,5,6都可回收:
      这里写图片描述
      垃圾收集算法
      标记-清理算法:首先,标记需要清除的对象,然后清除被标记的对象。缺点是,碎片化太严重。
      复制算法:新生代使用的算法
      标记-整理:比标记-清理,多出整理这一步。老生代使用的算法
      分代收集算法:复制算法和标记-整理算法的简单相加。
      垃圾收集器
      盗来的图:
      这里写图片描述
      新生代(复制算法):Serial(单线程),ParNew(多线程),Parallel (注重吞吐量)
      老生代(标记-整理):Serial Old,CMS,Parallel Old

对象访问

事实上,堆中对象除了存储对象本身外,还要存储其类型信息,而类型信息存储于方法区,那么该对象就需要存储一个指向方法区的指针。
当使用一个引用reference访问对象时,主流的访问方式有两种:句柄访问方式直接指针访问方式
句柄访问方式:两个指针,一个指向真实的对象,一个指向类型信息(堆中两个指针,一个对象);
如图:这里写图片描述
直接指针访问方式:真实的对象和指向类型信息的指针(堆中一个指针,一个对象)。
如图:这里写图片描述

聪明的你一定会疑问,为什么要有句柄访问方式,多此一举,直接指针就好了,干嘛要多出一个指针来,我选择第二种。事实上,sun Hotspot虚拟机也选用的第二种。可存在必合理,第一种到底是基于什么考虑?
共识:垃圾收集时,堆中的对象移动是非常普遍的行为(前面讲到了)。如果采用句柄式的话,就无需改变reference的值,只需要改变一个指向对象本身的指针即可。直接访问方式的话,当对象移动时,那就需要改变reference的值了。
直接访问方式的优势也就是访问速度更快,节省一次指针定位的时间,由于对象访问在程序中非常频繁,HotSpot虚拟机也是基于这种考虑吧!
疑惑:当对象移动时,我们在使用HotSpot虚拟机下写程序时,并未手动改变过reference的值,reference又是怎么定位到已经移动过的对象的?这次笔者真是不知道了
又是万能的知乎:当发生一次GC时,对象移动之后会自动刷新一次引用reference。似乎想的通,希望大神们不吝赐教。


思考总结:
“对象存放于堆,基本类型存放于栈”,这句话准确吗?如果准确,怎么对应于上面的区域?否则,哪里不准确?
答案是不准确。
不知道大家有没有发现,上面的解释叙述了类变量存放于方法区;实例变量中,全局对象存放于堆中,局部变量基本类型和对象引用存放于虚拟机栈中,对象实例存放于堆。唯独没有说明全局基本类型存放的位置,网上大部分说的对象存放于堆,基本类型存放于栈这种说法,可观众朋友们,你们是学习过Java虚拟机的高级程序员,能这么肤浅吗?就算是栈,就那两栈,谁能收留基本类型?没有一个。
万能的知乎已经告诉了我们答案,是堆!话不多说,
进入副本看答案,我就不搬运了。
下一节,讲解类文件结构,想想以后可以自己可以将calss文件反编译为Java代码,是不是还有点小激动,骚年,我看好你。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我看Java虚拟机(2)---Java虚拟机内存区域详解 的相关文章

  • 如何在日期选择器中设置不在当前月份的单元格的样式

    我目前正在为我的 JavaFX 应用程序制作注册表 问题是 当日期选择器中的单元格不在页面的月份上时 我想让该单元格变灰 让我们看看我当前的日期选择器 我的日期选择器 正如您所看到的 我希望下个月的日期 27 日 28 日 30 日以及 1
  • 在 JTable 中移动行

    我使用 MVC 模式 并且有一个如下所示的 JTable List
  • Java 中的 XPath 节点集

    我在 eclipse 中有这段代码 NodeSet nodes NodeSet xPath evaluate expression inputSource XPathConstants NODESET 它给我 NodeSet 上的编译时错误
  • 如何将 Java 赋值表达式转换为 Kotlin

    java中的一些东西就像 int a 1 b 2 c 1 if a b c System out print true 现在它应该转换为 kotlin 就像 var a Int 1 var b Int 2 var c Int 1 if a
  • AES 加密 Java/plsql

    我需要在Java和plsql DBMS CRYPTO for Oracle 10g 上实现相同的加密 解密应用程序 两种实现都工作正常 但这里的问题是我对相同纯文本的加密得到了不同的输出 下面是用于加密 解密过程的代码 Java 和 PLS
  • 解决错误:日志已在具有多个实例的atomikos中使用

    我仅在使用atomikos的实时服务器上遇到问题 在我的本地服务器上它工作得很好 我在服务器上面临的问题是 init 中出错 日志已在使用中 完整的异常堆栈跟踪 java lang RuntimeException Log already
  • JNI 不满意链接错误

    我想创建一个简单的 JNI 层 我使用Visual studio 2008创建了一个dll Win 32控制台应用程序项目类型 带有DLL作为选项 当我调用本机方法时 出现此异常 Exception occurred during even
  • 迁移到 java 17 后有关“每个进程的内存映射”和 JVM 崩溃的 GC 警告

    我们正在将 java 8 应用程序迁移到 java 17 并将 GC 从G1GC to ZGC 我们的应用程序作为容器运行 这两个基础映像之间的唯一区别是 java 的版本 例如对于 java 17 版本 FROM ubuntu 20 04
  • 序列化对象以进行单元测试

    假设在单元测试中我需要一个对象 其中所有 50 个字段都设置了一些值 我不想手动设置所有这些字段 因为这需要时间而且很烦人 不知何故 我需要获得一个实例 其中所有字段都由一些非空值初始化 我有一个想法 如果我要调试一些代码 在某个时候我会得
  • 归并排序中的递归:两次递归调用

    private void mergesort int low int high line 1 if low lt high line 2 int middle low high 2 line 3 mergesort low middle l
  • 将多模块 Maven 项目导入 Eclipse 时出现问题 (STS 2.5.2)

    我刚刚花了最后一个小时查看 Stackoverflow com 上的线程 尝试将 Maven 项目导入到 Spring ToolSuite 2 5 2 中 Maven 项目有多个模块 当我使用 STS 中的 Import 向导导入项目时 所
  • 使用 Flyway 和 Hibernate 的 hbm2ddl 在应用程序的生命周期中管理数据库模式

    我正在开发 Spring Hibernate MySql 应用程序 该应用程序尚未投入生产 我目前使用 Hibernatehbm2ddl该功能对于管理域上的更改非常方便 我也打算用Flyway用于数据库迁移 在未来的某个时候 该应用程序将首
  • Tomcat 6找不到mysql驱动

    这里有一个类似的问题 但关于类路径 ClassNotFoundException com mysql jdbc Driver https stackoverflow com questions 1585811 classnotfoundex
  • 运行 Jar 文件时出现问题

    我已将 java 项目编译成 Jar 文件 但运行它时遇到问题 当我跑步时 java jar myJar jar 我收到以下错误 Could not find the main class myClass 类文件不在 jar 的根目录中 因
  • 如何配置eclipse以保持这种代码格式?

    以下代码来自 playframework 2 0 的示例 Display the dashboard public static Result index return ok dashboard render Project findInv
  • 查看Jasper报告执行的SQL

    运行 Jasper 报表 其中 SQL 嵌入到报表文件 jrxml 中 时 是否可以看到执行的 SQL 理想情况下 我还想查看替换每个 P 占位符的值 Cheers Don JasperReports 使用 Jakarta Commons
  • KeyPressed 和 KeyTyped 混淆[重复]

    这个问题在这里已经有答案了 我搜索过之间的区别KeyPressedand KeyTyped事件 但我仍然不清楚 我发现的一件事是 Keypressed 比 KeyTyped 首先被触发 请澄清一下这些事件何时被准确触发 哪个适合用于哪个目的
  • 中断连接套接字

    我有一个 GUI 其中包含要连接的服务器列表 如果用户单击服务器 则会连接到该服务器 如果用户单击第二个服务器 它将断开第一个服务器的连接并连接到第二个服务器 每个新连接都在一个新线程中运行 以便程序可以执行其他任务 但是 如果用户在第一个
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item

随机推荐

  • C语言学习

    目录 调试 基本概念 bug 调试 debug 调试步骤 Debug和Release VS是集成开发环境 IDE 调试的快捷键 调试窗口 监视 减少程序的错误 assert 表达式 const 变量 调试 基本概念 bug 虫子 bug引申
  • 梦之光芒ctf小游戏闯关过程

    梦之光芒ctf游戏闯关 简介 玩这个游戏 您需要有JS 编码解码 XSS SQL注入 图片隐写 逆向分析等基本常识 游戏地址 http monyer com game game1 进入第1关 入口提示 请点击链接进入第1关 连接在左边 连接
  • max_binlog_size

    max binlog size 默认就是一个G最大值 但是有有什么会发现超过了一个G 原因就是 If a write to the binary log causes the current log file size to exceed
  • java application.yml 配置对象数组

    java application yml 配置对象数组 application yml 配置对象数组 常规对象中获取属性 场景 application yml 配置对象数组 定义配置文件结构 用于定义配置文件的数据结构 打印服务中用到的打印
  • Thinkpad在linux(ubuntu)下修改电池充电阈值,成功解决Thinkpad在Linux下的电池充电问题

    look this for more info http www thinkwiki org wiki Tp smapi 安装tp smapi aptitude install tp smapi dkms modprobe tp smapi
  • Kubernetes弃用Docker的由来和始末

    2020年12月初 Kubernetes在发布v1 20的时候重磅宣称将逐渐弃用Docker 一石激起千层浪 瞬间引爆容器圈 但没想到已经过去两个月时间了 还有文章用UC体误导吃瓜群众 还在学Docker Docker已死 额 累了 毁灭吧
  • mysql join 自己_用JOIN自己更新MySql

    HI我有查詢選擇了主鍵 id 1或外鍵 1的所有行 這是自己的連接 用JOIN自己更新MySql 選擇 SELECT f2 wz AS wz FROM d7x6r magazyn faktura zakupowa f LEFT JOIN S
  • 强化学习——基本概念

    什么是强化学习 强化学习关注与智能体 agent 如何与环境交互中不断学习以完成特定的目标 与有监督学习相比 不需要告诉智能体数据以及对应的标签 学习相应的模型 而是需要智能体在环境中一次次学习 哪些数据对应哪些标签 从而学习规律知道策略
  • Oracle 数据导入*.sql 提示ORA-01950

    今天执行远程Oracle 数据库数据导入时 提示ORA 01950 超出导入文件大小限制 cmd 远程连接oracle 数据库 sqlplus root root1234 192 50 68 246 orcl 导入指定位置的 sql文件 E
  • 双向广度优先搜索(介绍)

    双向广度优先搜索 广度优先搜索遵循从初始结点开始一层层扩展直到找到目标结点的搜索规则 它只能较好地解决状态不是太多的情况 承受力很有限 如果扩展结点较多 而目标结点又处在较深层 采用前文叙述的广度搜索解题 搜索量巨大是可想而知的 往往就会出
  • http请求 405错误

    http请求 405错误 方法不被允许 Method not allowed 405错误常常伴随着POST请求 所有有人会告诉你这些 但是时候他并不能解决你的问题 所以我说一点不一样的 假如你有一个user类 里面有两个属性userName
  • nat技术简介(转载)

    NAT Network Address Translation 网络地址转换 是将IP数据报文头中的IP地址转换为另一个IP地址的过程 在实际应用中 NAT主要用于实现私有网络访问公共网络的功能 这种通过使用少量的公网IP地址代表较多的私网
  • 快速搭建你的api数据交易平台-图文开发教程

    项目背景 如果你需要开发搭建自己的api数据交易平台 并且能在平台上面进行对客户管理 接口管理 套餐管理 账单管理 充值管理 那么下面将来介绍如何使用接口大师这个框架快速进行开发 安装 PhalApi专业版的运行环境要求如下 操作系统 Wi
  • nVidia TK1 基于深度学习框架 Caffe 的物体识别

    By Toradex 胡珊逢 1 简介 深度学习目前正吸引着越来越多人的关注 相关算法框架层出不穷 例如TensorFlow Caffe Keras CNTK Torch7等等 这些算法在数据分析 聚类 识别和预测方面提供了极大的帮助 因此
  • Python爬虫-某网酒店数据

    前言 本文是该专栏的第5篇 后面会持续分享python爬虫案例干货 记得关注 本文以某网的酒店数据为例 实现根据目标城市获取酒店数据 具体思路和方法跟着笔者直接往下看正文详细内容 附带完整代码 正文 地址 aHR0cHM6Ly93d3cuY
  • 基于核概念的KCCA算法

    基于核概念的KCCA算法 1 由CCA算法过渡至KCCA算法 2 KCCA算法的原理与推导 1 由CCA算法过渡至KCCA算法 典型相关分析 CCA 算法是一种标准的统计技术 用于寻找两个最大相关的随机向量的线性投影 CCA算法是一个计算两
  • 字符串初始化赋值

    在C语言中 字符串是当做字符数组来处理的 所以字符串有两种声明方式 一种是字符数组 一种是字符指针 1 直接逐个初始化字符数组 字符数组的初始化 最容易理解的方式就是逐个字符赋给数组中各元素 char str 10 I a m h a p
  • 单片机毕设项目分享 基于stm32的智能电子秤系统 - 物联网 嵌入式 单片机

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 设计原理 4 1 STM32F103C8T6 4 2 HX711压力传感器 5 部分核心代码 6 最后 0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目
  • Linux下安装jre

    原文链接 https blog csdn net qq 34368587 article details 79559102 个人收藏教程 侵权联系我删除 现需要项目部署到Linux中 需要配置java运行环境 注 以下测试环境系统为cent
  • 我看Java虚拟机(2)---Java虚拟机内存区域详解

    虚拟机内存区域的组成 直接上图 程序计数器 对于Java方法 用来选取下一条要执行的字节码 对于本地方法 值为空 线程独有 虚拟机栈 执行Java方法 每一层都是一个栈帧 栈帧包括局部变量表 操作数栈 动态链接和方法出口等信息 线程独有 本