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)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
什么是CRM系统,它的作用是什么?解读5个核心功能
上一篇 2025年11月15日 14:07:07
移民行业引入CRM会达到什么效果?探讨3个行业优势
下一篇 2025年11月15日 14:07:22

相关推荐

  • mysql如何输入特殊字符 mysql写sql语句的转义方法

    mysql如何输入特殊字符 mysql写sql语句的转义方法mysql如何输入特殊字符 mysql写sql语句的转义方法mysql如何输入特殊字符 mysql写sql语句的转义方法mysql如何输入特殊字符 mysql写sql语句的转义方法

    在mysql中处理特殊字符的核心方法是使用预处理语句,1.手动转义可通过反斜杠实现,如单引号转为’、双引号转为”等,但易出错且不安全;2.更推荐使用预处理语句(prepared statements)或参数绑定,它能自动处理特殊字符并防止sql注入;3.预处理语句的优势包括安全性高,彻底杜绝sql注…

    2026年9月23日 用户投稿
    400
  • VSCode运行多文件C项目 完整VSCode配置C++开发教程

    要解决#%#$#%@%@%$#%$#%#%#$%@_e2fc++805085e25c9761616c00e065bfe8运行多文件c项目的问题,核心是正确配置tasks.json、launch.json和settings.json文件以定义编译、调试和项目路径。首先安装c/c++扩展插件和可选的编译…

    2026年9月22日
    100
  • Linux内核13-进程切换

    进程切换,也称为任务切换、上下文切换或任务调度,本文将探讨linux内核中进程切换的实现。我们首先理解几个关键概念。 1.1 硬件上下文 每个进程都有自己的地址空间,但所有进程共享CPU寄存器。因此,在恢复进程执行前,内核必须确保挂起时的寄存器值被重新加载到CPU寄存器中。 这些需要加载到CPU寄存…

    2026年9月22日
    300
  • VSCode安装C/C++插件 小白必备VSCode配置C语言教程

    安装C/C++插件并配置MinGW编译器,通过tasks.json和launch.json文件设置编译调试任务,可使VSCode支持C语言开发;若插件异常,需检查环境变量、文件路径及语法,必要时重启或重装;中文乱码可通过设置UTF-8编码、使用集成终端或程序内setlocale解决;远程开发需配合R…

    2026年9月22日
    100
  • VSCode快速配置Markdown:实时预览、中文排版、导出PDF

    答案:通过安装Markdown All in One和Markdown PDF扩展,并配置自定义CSS文件优化中文字体、行高及排版样式,可在VSCode中实现Markdown实时预览、中文排版优化和高质量PDF导出,结合settings.json设置可进一步支持页眉页脚、自动转换等功能,提升文档编写…

    2026年9月22日
    100
  • VSCode安装C/C++文档查看 提升开发效率的VSCode技巧

    答案是利用C/C++扩展和cppreference插件实现高效文档查阅。首先安装微软官方C/C++扩展,启用智能感知与悬停提示;再安装cppreference扩展,通过命令面板直接搜索标准库函数,实现离线在线无缝查阅;结合Doxygen生成项目文档,使用“转到定义”功能快速跳转源码;同时借助Inte…

    2026年9月22日
    100
  • rm -rf 误删文件?别急,或许有救!

    rm -rf 误删文件?别急,或许有救!rm -rf 误删文件?别急,或许有救!rm -rf 误删文件?别急,或许有救!rm -rf 误删文件?别急,或许有救!

    立即采取行动! 在生产环境中,我们应尽量避免进行风险操作。但如果不慎犯错,如何挽救呢?让我分享一个故事:上周我为了打包一个应用,需要整理Ubuntu 16.04上的线上数据,不小心删除了一个数据文件,幸而最终有惊无险,现记录如下。 extundelete 我的恢复计划主要依赖于一个工具——extun…

    2026年9月22日 用户投稿
    000
  • python 基准测试(cProfile kcachegrind line_profiler memory_profiler)

    learn from 《python高性能(第2版)》 类似工具:pycharm profile对函数调用效率进行测试 1. 例子 一个圆周运动的动画 代码语言:javascript代码运行次数:0运行复制 from matplotlib import pyplot as pltfrom matpl…

    2026年9月22日
    200
  • VSCode安装C/C++开发环境 最新VSCode配置C语言教程详解

    答案:搭建VSCode的C/C++环境需安装编译器、C/C++扩展并配置项目文件。首先安装MinGW(Windows)、Clang(macOS)或GCC(Linux),配置环境变量并验证;然后在VSCode中安装Microsoft的C/C++扩展;最后创建.c_cpp_properties.json…

    2026年9月22日
    300
  • VSCode配置GDB调试器 深入掌握VSCode调试C程序技巧

    配置vscode中gdb调试c程序的核心是正确设置tasks.json和launch.json;2. tasks.json负责使用gcc -g编译生成带调试信息的可执行文件,确保prelaunchtask与launch.json中的program路径一致;3. launch.json指定调试器gdb…

    2026年9月22日
    100
  • VSCode配置C语言调试环境 从零开始VSCode搭建C开发工具

    要从零开始在#%#$#%@%@%$#%$#%#%#$%@_e2fc++805085e25c9761616c00e065bfe8中搭建c语言开发和调试环境,首先需安装vscode本体、c/c++编译器(如mingw或gcc)并配置系统环境变量,接着安装vscode的c/c++扩展,然后创建项目并编写c…

    2026年9月22日
    100
  • 递归实现列表排序检查与条件移除最大值

    本文详细介绍了如何使用Java递归方法处理整数列表。核心内容包括:首先检查列表是否已排序,如果已排序则直接返回false;如果未排序,则查找列表中的最大值。仅当最大值位于列表的起始或结束位置时,才将其移除并递归地继续处理列表。如果最大值位于列表中间,则打印当前列表并终止递归。 在数据处理和算法设计中…

    2026年9月22日
    100
  • Linux中如何安装Redis_Linux安装Redis服务的完整教程

    安装编译环境和依赖:Ubuntu/Debian用apt安装build-essential tcl wget,CentOS/RHEL用yum安装Development Tools和tcl wget。2. 下载Redis 7.2.4源码包并%ignore_a_1%,进入目录后执行make编译,可选mak…

    2026年9月21日
    000
  • 如何在Java中实现简单的输入输出

    使用Scanner类读取键盘输入,需导入java.util.Scanner并创建实例;2. 调用nextInt、nextLine等方法获取不同类型数据,注意nextInt不读取换行符可能导致nextLine读取空字符串;3. 推荐使用后关闭Scanner;4. 输出通过System.out.prin…

    2026年9月21日
    000
  • Java中类与对象的内存结构详解

    类信息存方法区,对象实例在堆中,引用在栈中;静态变量共享,实例变量独立。 在Java中,类与对象的内存结构是理解程序运行机制的关键。当一个Java程序执行时,JVM(Java虚拟机)会管理不同的内存区域,如堆、栈、方法区等。类和对象在这些区域中的分布直接影响程序的性能与行为。 类信息存储在方法区 类…

    2026年9月13日
    100
  • 如何在mysql中使用字符串连接符实现字段拼接

    使用CONCAT()和CONCAT_WS()函数实现MySQL字符串拼接,前者用于常规拼接,后者可跳过NULL值并添加分隔符,避免结果为NULL,推荐优先使用以确保兼容性和正确性。 在 MySQL 中,字符串拼接不能使用像其他编程语言中的 + 或 || 符号,而是通过内置函数或操作符来实现。最常用的…

    2026年9月12日
    200
  • VSCode 的扩展更新策略是自动还是手动,如何控制以避免意外?

    VSCode扩展默认自动更新,但可手动控制以平衡便利与稳定性。用户可通过设置”extensions.autoUpdate”选择自动或禁用更新,并利用@outdated筛选待更新扩展。对关键扩展建议禁用自动更新以避免兼容性问题,同时定期手动检查更新日志,确保安全与功能同步。若更…

    2026年9月11日
    200
  • YII框架的版本迁移是什么?YII框架如何升级版本?

    YII框架版本迁移需谨慎规划,答案是升级前应评估成本与收益,使用Composer管理依赖,重构命名空间,调整核心组件、数据库迁移、事件处理及模板引擎,充分测试并参考官方文档;YII1到YII2需注意PHP版本、类名变更、配置格式、URL管理、表单处理、扩展兼容性及错误处理;回滚时须备份、使用版本控制…

    2026年9月11日
    200
  • Swoole如何做性能分析?分析工具有哪些?

    Swoole性能分析需结合内置监控与外部工具,先通过SwooleServer::stats()和系统监控定位异常,再用perf、strace或Blackfire等工具深入分析CPU、内存、I/O瓶颈,尤其关注协程阻塞与隐性同步操作,最后通过火焰图可视化热点,迭代优化并验证效果。 Swoole的性能分…

    2026年9月11日
    200
  • Swoole如何处理大JSON数据?JSON解析如何优化?

    Swoole处理大JSON时,核心在于非阻塞I/O与异步解析结合。首先,json_decode是CPU密集型操作,会阻塞Worker进程,导致内存激增、响应延迟和并发下降。其次,推荐采用流式解析库(如json-machine)逐块处理数据,降低内存占用。最后,利用Swoole的Task Worker…

    2026年9月11日
    000

发表回复

登录后才能评论
关注微信