核心内容摘要
OFA-VE在嵌入式系统的轻量化部署:基于STM32的视觉分析方案
HoRain 云小助手个人主页⛺️生活的理想就是为了理想的生活!⛳️ 推荐前些天发现了一个超棒的服务器购买网站性价比超高大内存超划算忍不住分享一下给大家。
点击跳转到网站。
目录⛳️ 推荐 核心内存区域详解
程序计数器执行线索的记录者
Java 虚拟机栈方法执行的现场
本地方法栈Native 方法的支持
堆对象生存的乐园
方法区类型信息的仓库 内存管理的演进从永久代到元空间️ 垃圾回收与内存模型
总结与实践建议理解 Java 虚拟机JVM内存模型对于编写稳健、高性能的 Java 应用至关重要。
它就像是 Java 程序运行的“城市布局”不同区域承担不同职能同时又需要高效的“市政管理”垃圾回收来保持秩序。
下面这张表格汇总了各核心区域的关键信息帮你快速建立整体认知。
内存区域线程关系核心功能生命周期异常错误程序计数器线程私有存储当前线程所执行的字节码行号指示器实现流程控制分支、循环、跳转等。
与线程共存亡无Java 虚拟机栈线程私有存储方法执行的栈帧包括局部变量表、操作数栈、动态链接、方法出口信息等 。
与线程共存亡StackOverflowError栈深度超限OutOfMemoryError扩展时内存不足本地方法栈线程私有为虚拟机使用到的 Native 方法服务 。
与线程共存亡StackOverflowErrorOutOfMemoryError堆线程共享存放对象实例和数组是垃圾回收的主要区域 。
虚拟机启动时创建OutOfMemoryError内存不足且无法扩展方法区线程共享存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据 。
虚拟机启动时创建OutOfMemoryError内存不足且无法扩展 核心内存区域详解
程序计数器执行线索的记录者程序计数器是一块较小的内存空间可以看作是当前线程所执行的字节码的行号指示器 。
在多线程环境下Java 虚拟机通过时间片轮转的方式实现并发执行。
当线程切换发生时程序计数器能确保线程恢复执行时能知道接下来该执行哪条指令 。
执行 Java 方法时它记录的是虚拟机字节码指令的地址执行 Native 方法时其值为空 (Undefined) 。
此区域是唯一一个在 Java 虚拟机规范中没有规定任何OutOfMemoryError情况的区域 。
Java 虚拟机栈方法执行的现场每个方法在执行时都会在虚拟机栈中创建一个栈帧用于存储方法运行所需的各种信息 。
局部变量表存放编译期可知的基本数据类型如int,boolean等、对象引用reference类型和returnAddress类型。
其中 64 位的long和double会占用 2 个局部变量空间Slot其余占用 1 个 。
局部变量表的大小在编译期确定。
操作数栈用于方法执行过程中的计算。
动态链接将符号引用转换为直接引用。
方法出口记录方法返回的地址。
当线程请求的栈深度大于虚拟机所允许的深度例如无限递归会抛出StackOverflowError。
如果虚拟机栈可以动态扩展大部分虚拟机都可动态扩展但在扩展时无法申请到足够内存则会抛出OutOfMemoryError。
本地方法栈Native 方法的支持本地方法栈与虚拟机栈作用类似区别在于虚拟机栈为执行 Java 方法服务而本地方法栈则为虚拟机使用到的 Native 方法服务 。
HotSpot 虚拟机直接把本地方法栈和虚拟机栈合二为一 。
堆对象生存的乐园堆是 Java 虚拟机管理中最大的一块内存区域被所有线程共享在虚拟机启动时创建。
此区域的唯一目的就是存放对象实例和数组 。
堆是垃圾收集器管理的主要区域因此也被称为 “GC 堆” 。
从内存回收角度Java 堆可细分为新生代Young Generation和老年代Old Generation/Tenured Generation新生代又可细分为 Eden 空间和 Survivor 空间From Survivor, To Survivor目的是为了更好地进行内存回收和分配 。
方法区类型信息的仓库方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 。
方法区是 JVM 规范定义的逻辑部分具体实现因版本和虚拟机而异。
在 JDK 8 之前HotSpot 虚拟机使用永久代来实现方法区。
从 JDK 8 开始永久代被移除取而代之的是元空间它使用本地内存Native Memory而非 JVM 内存从而避免了永久代的内存溢出问题如java.lang.OutOfMemoryError: PermGen space其大小仅受本地内存限制 。
运行时常量池是方法区的一部分用于存放 Class 文件常量池中的符号引用和翻译出来的直接引用具备动态性如String.intern()方法可在运行期间将新的常量放入池中。
在 JDK 7 时字符串常量池已被移至堆中 。
内存管理的演进从永久代到元空间特性永久代JDK 7 及以前元空间JDK 8 及以后实现位置JVM 堆内存中本地内存Native Memory内存限制受 JVM 堆大小参数如-XX:MaxPermSize限制默认仅受本地内存大小限制可通过-XX:MaxMetaspaceSize设定上限主要优势与 JVM 堆统一管理避免永久代内存溢出提升元数据管理灵活性利于简化 GC 复杂度主要挑战易出现java.lang.OutOfMemoryError: PermGen space类元信息大小难确定设置困难需要关注本地内存使用情况️ 垃圾回收与内存模型堆是垃圾收集器工作的主要区域。
为了更高效地回收内存堆被划分为新生代和老年代。
新生代与 Minor GC大多数新创建的对象首先分配在 Eden 区。
当 Eden 区满时会触发一次Minor GC。
存活的对象会被移动到 Survivor 区S0, S1并在 Survivor 区中经历多次 Minor GC 后年龄Age达到阈值默认 15的对象会晋升到老年代 。
新生代 GC 采用复制算法因为新生代的对象存活率低复制算法的效率高 。
老年代与 Full GC老年代存放长期存活的对象。
当老年代空间不足或方法区元空间空间不足时会触发Full GC其速度通常比 Minor GC 慢 10 倍以上。
老年代 GC 一般采用标记-清除或标记-整理算法 。
总结与实践建议理解核心分区牢记程序计数器、虚拟机栈、本地方法栈、堆和方法区这五大核心区域及其线程属性、功能和异常。
关注版本演进理解 JDK 8 中方法区从永久代到元空间的转变及其意义这有助于避免配置错误和内存溢出。
善用 JVM 参数根据应用特点合理设置堆大小-Xms,-Xmx、元空间大小-XX:MaxMetaspaceSize、线程栈大小-Xss等参数对性能调优至关重要。
掌握异常诊断遇到StackOverflowError通常意味着代码中存在过深递归或大量循环调用而OutOfMemoryError则需分析是堆内存不足、元空间不足还是其他原因。
希望这份详细的解析能帮助你深入理解 JVM 内存模型如果你对垃圾回收算法的具体细节或性能调优实战有兴趣我们可以继续深入探讨。
❤️❤️❤️本人水平有限如有纰漏欢迎各位大佬评论批评指正如果觉得这篇文对你有帮助的话也请给个点赞、收藏下吧非常感谢! Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧