JVM 内存结构基于JDK1.8【JVM篇三】

大家好,我们又见面了,我是你们的朋友全栈君。

在上一篇文章《别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】》中,相信大家已经对Java类加载机制有了全面的了解。那么,类加载之后,字节码数据在Java虚拟机内存中是如何存放的?Java虚拟机在为类实例或成员变量分配内存时是如何分配的?这两个问题涉及到了JVM内存结构的知识,这篇文章将为大家解答。

文章目录:1、内存结构还是运行时数据区?2、运行时数据区3、线程共享:Java堆、方法区3.1、Java堆3.2、JVM堆内存溢出后,其他线程是否可继续工作?3.3、方法区3.4、JDK1.8之前的方法区3.5、JDK1.8之后的方法区3.6、JDK1.8之后的方法区为何变化如此之大?4、线程私有:程序计数器、Java虚拟机栈、本地方法栈4.1、Java虚拟机栈(JVM Stacks)4.2、本地方法栈(Native Method Stacks)4.3、程序计数器5、JVM内存结构总结

1、内存结构还是运行时数据区?要解答本文提到的这些问题,我们首先需要了解一下Java虚拟机的内存结构。

2、运行时数据区JVM被分为三个主要的子系统:类加载器子系统、运行时数据区和执行引擎。本文主要讲解其中的运行时数据区(Runtime Data Areas)。

JVM 内存结构基于JDK1.8【JVM篇三】在Java虚拟机规范中,定义了五种运行时数据区,分别是Java堆、方法区、虚拟机栈、本地方法区、程序计数器。

顺便提一下,运行时常量池也会进入方法区,也就是说方法区中已经包括了常量池。

JVM 内存结构基于JDK1.8【JVM篇三】

3、线程共享:Java堆、方法区我们首先来了解一下线程共享的Java堆和方法区。

3.1、Java堆Java堆是内存空间中占用的最大一块区域,用于存放对象实例及数组,也就是说我们代码中通过new关键字创建的对象都存放在这里。因此,这里也是垃圾回收器的主要活动场所,被称为GC堆。每个JVM进程只有一个Java堆。根据垃圾回收器的规则,我们可以对Java堆进行进一步的划分,具体Java堆内存结构如下图所示:

JVM 内存结构基于JDK1.8【JVM篇三】从上图可以看出,Java堆并不是单纯的一整块区域,实际上Java堆根据对象存活时间的不同,被分为年轻代和老年代两个区域。年轻代还被进一步划分为Eden区、From Survivor 0区和To Survivor 1区。默认的虚拟机配置比例是Eden:From:To = 8:1:1。

仔细看过上面的Java堆结构图的朋友可能会发现-Xms和-Xmn的字样,这正是控制堆的JVM参数。我们可以通过JVM参数动态控制Java堆中的各空间大小。JVM的参数有很多,但常用的就那么几个,用多了很容易记住。下面我们来讲讲关于堆的常见JVM参数:

当Java堆内没有足够的空间去完成实例分配,并且堆也无法扩展时,将会抛出常见的OutOfMemoryError异常,也就是我们常说的OOM异常。

3.2、JVM堆内存溢出后,其他线程是否可继续工作?JVM堆内存溢出后,也就是OOM异常,网上有一道非常火的面试题:JVM堆内存溢出后,其他线程是否可继续工作?

实际上这个问题需要具体场景分析。但是一般情况下,发生OOM的线程都会终止(除非代码写的太烂),该线程持有的对象占用的heap都会被GC回收,释放内存。因为发生OOM之前要进行GC,即便其他线程能够正常工作,也会因为频繁的GC产生较大的影响。

也就是说,发生OOM的线程一般情况下会死亡,也就是会被终止,该线程持有的对象占用的heap都会被GC回收,释放内存。因为发生OOM之前要进行GC,即便其他线程能够正常工作,也会因为频繁的GC产生较大的影响。

3.3、方法区方法区(Method Area)与上面讲的Java堆一样,都是各个线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它有一个别名叫做Non-Heap(非堆),目的是与Java堆区分开来。

3.4、JDK1.8之前的方法区就以HotSpot虚拟机来说,在JDK1.8之前,方法区也被称作为永久代。这个方法区会发生我们常见的java.lang.OutOfMemoryError: PermGen space异常,注意是永久代异常信息,我们也可以通过启动参数来控制方法区的大小。

在JDK7之前的HotSpot虚拟机中,纳入字符串常量池的字符串被存储在永久代中,因此导致了一系列的性能问题和内存溢出错误。特别突出的例子就是String的intern()方法。

3.5、JDK1.8之后的方法区JDK8之后就没有永久代这一说法,取而代之的是元空间(meta space),而且将老年代与元空间剥离。元空间放置于本地的内存中,因此元空间的最大空间就是系统的内存空间,从而不会再出现像永久代的内存溢出错误,也不会出现泄漏的数据移到交换区这样的事情。用户可以为元空间设置一个可用空间最大值,不设置的话默认根据类的元数据大小动态增加元空间的容量。对于一个64位的服务器端JVM来说,其默认的-XX:MetaspaceSize值为21MB。也就是说,默认的元空间大小是21MB。

只要类加载器还存活,其加载的类的元数据也是存活的,不会被回收掉,也就是同生共死。

JVM 内存结构基于JDK1.8【JVM篇三】

3.6、JDK1.8之后的方法区为何变化如此之大?做这个改变主要是基于以下两点原因:

1、由于永久代(PermGen)内存经常会溢出,引发恼人的java.lang.OutOfMemoryError: PermGen,因此JVM的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的OOM错误。

2、移除永久代(PermGen)可以促进HotSpot JVM与JRockit VM的融合,因为JRockit没有永久代。

4、线程私有:程序计数器、Java虚拟机栈、本地方法栈Java堆以及方法区的数据是共享的,但是有一些部分是线程私有的。线程私有部分可以分为:程序计数器、Java虚拟机栈、本地方法栈三大部分。

4.1、Java虚拟机栈(JVM Stacks)1、Java虚拟机的每一条线程都有自己私有的Java虚拟机栈,这个Java虚拟机栈与线程同时创建,因此它与线程有相同的生命周期。

2、Java虚拟机栈描述的是Java方法执行的内存模型:每一个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在Java虚拟机栈中的入栈到出栈的过程。

3、局部变量表存放了编译期可知的各种基本数据类型、对象引用和returnAddress类型。其中64位长度的long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

4、Java虚拟机栈既允许被实现成固定的大小,也允许根据计算动态扩展和收缩。如果采用固定大小的话,每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定。在Java虚拟机栈中会发生两种异常,这个在虚拟机规范中有指出:

如果线程请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机将会抛出StackOverflowError异常;也就是栈溢出错误!方法递归调用产生StackOverflowError异常这种结果。如果Java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存或者在创建新的线程时没有足够的内存去创建对应的Java虚拟机栈,那么虚拟机将会抛出OutOfMemoryError异常。也就是OOM内存溢出错误!(线程启动过多)当然,可以通过参数-Xss去调整JVM栈的大小。

4.2、本地方法栈(Native Method Stacks)和虚拟栈相似,只不过它服务于Native方法,线程私有。当Java虚拟机使用其他语言(例如C语言)来实现指令集解释器时,也会使用到本地方法栈。如果Java虚拟机不支持native方法,并且自己也不依赖传统栈的话,可以无需支持本地方法栈。

与Java虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

HotSpot虚拟机直接就把本地方法栈和虚拟机栈合二为一。

4.3、程序计数器当前线程所执行的字节码的行号指示器,用于记录正在执行的虚拟机字节指令地址,线程私有。

5、JVM内存结构总结JVM 内存结构基于JDK1.8【JVM篇三】程序计数器:

Java虚拟栈:

Native方法栈:

Java堆:

方法区:

发布者:全栈程序员栈长,转载请注明出处:https://www.php.cn/link/c0243062e292cce3284a1cd9a8e30300原文链接:https://www.php.cn/link/c8377ad2a50fb65de28b11cfc628d75c

以上就是JVM 内存结构基于JDK1.8【JVM篇三】的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/11229.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月15日 13:47:50
下一篇 2025年11月15日 14:14:17

相关推荐

  • Phaser 3 游戏画布响应式适配:保持高度控制宽度

    本文旨在提供一种在 Phaser 3 游戏中实现画布响应式适配的方案,核心思路是利用 `Phaser.Scale.HEIGHT_CONTROLS_WIDTH` 缩放模式,使画布高度适应父容器,宽度随之调整,并始终居中显示。这种方法适用于需要保持游戏核心内容在屏幕中央,允许左右裁剪的场景。 在 Pha…

    2025年12月6日 web前端
    000
  • Phaser 3游戏画布响应式布局:实现高度适配与宽度裁剪

    本文深入探讨phaser 3游戏画布在特定响应式场景下的布局策略,尤其是在需要画布高度适配父容器并允许左右内容裁剪时。通过结合phaser的scalemanager中的`height_controls_width`模式与精细的css布局,本教程将展示如何实现一个既能保持游戏画面比例,又能完美融入不同…

    2025年12月6日 web前端
    000
  • Java中long类型转换失效?理解表达式求值与整数溢出

    当在java中将一个可能溢出的整数表达式强制转换为long时,常见的错误是由于表达式在转换前已按int类型计算而导致溢出。本文将深入解释java的类型转换规则和运算符优先级,揭示为何直接对表达式进行long类型转换会失败,并提供两种确保大整数运算准确性的正确方法,帮助开发者避免潜在的数据丢失问题。 …

    2025年12月6日 java
    000
  • JavaScript中实现词干提取:识别词语基础形态与应用实践

    本文深入探讨了如何在javascript中实现词干提取,以识别词语的各种形态并匹配其基础形式。针对用户输入词语后,需高亮显示其所有变体的需求,文章介绍了porter和lancaster等主流词干提取算法及其在javascript中的实现库。同时,探讨了算法选择、多语言支持的局限性,并提供了相关学习资…

    2025年12月6日 web前端
    000
  • 如何在Laravel中配置Redis缓存

    在laravel中配置redis缓存的核心步骤包括安装并运行redis服务、安装php扩展或composer包、配置.env文件和config/database.php、清除缓存。1. 安装redis服务器:使用系统包管理工具安装并启动redis服务;2. 安装php扩展或predis包:选择php…

    2025年12月5日
    000
  • js如何实现水印效果 前端动态生成防泄密水印

    在javascript中实现水印效果主要有canvas水印和dom水印两种方式。1. canvas水印通过创建canvas元素并使用filltext()方法绘制文字,性能较好且不易被移除,但实现较复杂;2. dom水印则通过创建div元素设置样式来显示水印,更加灵活易控,但容易被用户修改或移除。动态…

    2025年12月5日 web前端
    000
  • js调试debug工具使用_js调试debug方法全解析

    调试javascript代码需掌握浏览器开发者工具如chrome devtools,使用console、sources、network、elements面板监控代码执行、设置断点、查看网络请求和操作dom;采用断点调试、console.log()、debugger语句分析错误,结合source ma…

    2025年12月5日 web前端
    000
  • linux下gdb调试方法与技巧整理「建议收藏」

    大家好,很高兴再次与大家见面,我是你们的老朋友全栈君。 目录一、gdb简介二、gdb使用流程1、启动gdb2、查看源码3、运行程序4、设置断点5、单步执行6、查看变量7、退出gdb三、gdb基本使用命令1、运行命令2、设置断点3、查看源码4、打印表达式5、查看运行信息6、分割窗口7、cgdb强大工具…

    2025年12月5日
    000
  • js怎样操作Web Serial API 串口设备通信的5个基础步骤

    处理 web serial api 的权限问题,需通过五个步骤:1. 使用 navigator.serial.requestport() 请求授权;2. 用户必须明确允许访问设备;3. 可用 retain 选项保存授权信息;4. 用 navigator.permissions.query() 检查权…

    2025年12月5日 web前端
    000
  • ucrtbase.dll运行库错误 原因及解决指南

    一、ucrtbase.dll是什么? ucrtbase.dll 是微软通用C运行时库(Universal C Runtime,简称UCRT)中的关键动态链接库文件,负责为基于C语言开发的程序提供基础运行支持。自Windows 10起,该运行库被集成进系统核心组件中,同时也包含在Visual C++ …

    2025年12月5日 电脑教程
    000
  • ThinkPHP的社区资源在哪里?ThinkPHP如何获取帮助?

    thinkphp的社区资源主要集中在官方论坛、github仓库、技术博客、问答平台及qq群、微信群等;2. 获取帮助的途径包括查阅官方文档、参与社区讨论、搜索教程、在论坛或stack overflow提问;3. thinkphp 6相比5.1在架构上更新,社区资源更侧重新特性与最佳实践,而5.1多集…

    2025年12月4日 PHP框架
    000
  • YII框架的扩展是什么?YII框架如何安装扩展?

    yii框架的扩展是为应用提供额外功能的代码包,可通过composer安装,步骤包括确保composer已安装、定位项目根目录、执行composer require命令,并在配置文件中注册组件、模块或引导项;2. 选择扩展时需考量活跃度与维护状态、文档完整性、社区支持、功能匹配度及代码质量;3. 安装…

    2025年12月4日
    000
  • React中怎么使用Portals渲染组件?

    react portal 允许将组件渲染到 dom 树之外,解决布局限制问题。1. 使用 reactdom.createportal 方法,指定要渲染的组件和目标 dom 节点;2. 创建 dom 节点并挂载到合适的位置(如 document.body);3. 在组件卸载时清理 dom 节点以避免内…

    2025年12月4日 web前端
    000
  • Java中WeakHashMap的作用 解析弱引用Map

    weakhashmap通过弱引用键实现自动回收机制,解决对象在不再强引用时仍占用map内存的问题。其核心在于当键仅被weakhashmap引用时,垃圾回收器可回收该键,随后weakhashmap在下次操作时清理对应条目。典型应用场景包括缓存系统,用于自动释放不再使用的昂贵对象。与hashmap的区别…

    2025年12月4日 java
    000
  • 解决SVG tspan getBBox() 在Firefox中返回错误值的方案

    本文旨在解决SVG tspan元素在Firefox浏览器中使用getBBox()方法时返回不准确或零值的问题。针对这一跨浏览器兼容性挑战,文章提供了两种有效的解决方案:一是利用父级元素的getBBox()获取整体文本范围,适用于仅需整体高度的场景;二是开发一个基于getExtentOfChar()的…

    2025年12月4日
    000
  • js如何检测内存泄漏 内存泄漏检测的5种实用技巧

    如何检测和避免javascript内存泄漏?使用chrome开发者工具进行内存泄漏检测:打开开发者工具,选择”memory”面板,点击”take heap snapshot”生成内存快照,分析detached dom tree、constructor和…

    2025年12月4日 web前端
    000
  • Socket 编程

    最近我在录制一套关于web页面获取mac地址的视频,这是一个真实项目中的案例,解决方案也经历了几次迭代。最终,我们通过使用socket api模拟http协议来解决这个问题。 以下是我录制的视频链接,《WEB端获取MAC地址真实项目案例》: https://www.php.cn/link/4e189…

    2025年12月3日
    000
  • Java中守护线程是什么 解析守护线程的特殊性质

    守护线程是java中一种特殊线程,其运行不影响jvm的退出。1. 守护线程用于执行后台任务如垃圾回收、资源监控、定时任务和日志服务等;2. 创建方式是通过调用setdaemon(true)方法且必须在线程启动前设置;3. 守护线程需注意数据完整性、资源释放及避免依赖关系;4. 与普通线程的区别在于j…

    2025年12月3日 java
    000
  • js如何实现进度条效果 js进度条动画的6种实现技巧

    进度条在js中通过动态更新视觉元素属性实现,核心步骤包括:1.html结构创建容器与进度条元素;2.css设置样式及过渡动画;3.js函数控制进度更新并模拟递增;4.应用css美化如渐变色、圆角、阴影;5.异步任务通过监听事件或轮询更新进度;6.封装为组件提升复用性;7.优化性能避免频繁dom操作和…

    2025年12月3日 web前端
    000
  • Java中如何优化GC 掌握JVM参数

    优化gc的核心是减少频率和停顿时间,通过理解jvm机制并调整参数实现。1.监控gc日志,使用-xlog:gc*分析频率、时间和原因;2.选择合适回收器,如g1兼顾吞吐与停顿,zgc低延迟但资源消耗高;3.调整堆内存大小,设置-xms和-xmx一致以避免性能损耗;4.调整新生代与老年代比例,合理设置n…

    2025年12月3日 java
    300

发表回复

登录后才能评论
关注微信