JVM(2):JVM内存结构

JVM内存模型和结构详解(五大模型图解) JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一个虚构出来的计算机,有着自己完善的硬件架构,如处理器、堆栈等。 阅读详情


所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问题就会变的非常常见,了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障。

先看一张图,这张图能很清晰的说明JVM内存结构布局。

Java的内存结构:

JVM内存结构主要有三大块:堆内存、方法区和栈。堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配;

方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为java虚拟机栈和本地方法栈主要用于方法的执行。

在通过一张图来了解如何通过参数来控制各区域的内存大小

控制参数
-Xms设置堆的最小空间大小。

-Xmx设置堆的最大空间大小。

-XX:NewSize设置新生代最小空间大小。

-XX:MaxNewSize设置新生代最大空间大小。

-XX:PermSize设置永久代最小空间大小。

-XX:MaxPermSize设置永久代最大空间大小。

-Xss设置每个线程的堆栈大小。

没有直接设置老年代的参数,但是可以设置堆空间大小和新生代空间大小两个参数来间接控制。

老年代空间大小=堆空间大小-年轻代大空间大小

从更高的一个维度再次来看JVM和系统调用之间的关系

方法区和堆是所有线程共享的内存区域;而Java栈、本地方法栈和程序计数器是运行是线程私有的内存区域。

下面我们详细介绍每个区域的作用

Java堆(Heap)

对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java堆中还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。

根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。

如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

方法区(Method Area)

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

对于习惯在HotSpot虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。

Java虚拟机规范对这个区域的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。

根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

程序计数器(Program Counter Register)

程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空(Undefined)。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

JVM栈(JVM Stacks)

与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。

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

在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

本地方法栈(Native Method Stacks)

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

参考:

http://ifeve.com/under-the-hood-runtime-data-areas-javas-memory-model/

《深入理解Java虚拟机:JVM高级特性与最佳实践_周志明.高清扫描版.pdf》


源自:http://www.importnew.com/23746.html

JVM内存模型详解 线程安全本质是由于多个线程对同一个堆内存中的Count变量操作的时候,每一个线程会在线程内部创建这个堆内存Count变量的副本,线程内所有的操作都是对这个Count副本进行操作。**本地方法栈:**本地方法栈保存的是native方法的信息,当一个JVM创建的线程调用native方法后,JVM不再为其在虚拟机栈中创建栈帧,**堆:**Java堆是程序员需要重点关注的一块区域,因为涉及到内存的分配(new关键字,反射等)与回收(回收算法,收集器等);方法的执行就对应着栈帧在虚拟机栈中入栈和出栈的过程; 阅读详情

相关推荐

JVM内存模型

Java内存模型 Java内存模型是共享内存的并发模型,线程之间主要通过读-写共享变量(堆内存中的实例域,静态域和数组元素)来完成隐式通信。 Java 内存模型(JMM)控制 Java 线程之间的通信,决定一个线程对共享变量的写入何时对另一个线程可见。 计算机高速缓存和缓存一致性 计算机在高速的 CPU 和相对低速的存储设备之间使用高速缓存,作为内存和处理器之间的缓...

十年代码写十年 1166

【JVM】JVM内存模型(详细)

JVM内存模型(详细)

酷酷的馫博客 5万+

深入Java虚拟机(2):JVM内存结构详解

我的上一篇讲了关于Java类的生命周期和类加载机制中有涉及到JVM虚拟机内存,这篇文章就详细介绍关于JVM内存的结构、内存中不同区域的主要职责,在描述各区域的职责的同时,还会说到具体不同内存区域中的具体结构空间以及这些结构布局的目的及特性,了解这些基础的东西对在今后学习或者工作开发当中出现了有关内存的问题就可以很快的定位问题然后解决问题,另外结合内存结构再学习关于垃圾回收相关的知识...

_xiaolin_ 1719

JVM系列2:内存结构

内存结构 程序计数器 虚拟机栈 本地方法栈 堆 方法区 直接内存 1. 程序计数器 1.1 定义 Program Counter Register 程序计数器(寄存器) 作用,是记住下一条jvm指令的执行地址 特点 是线程私有的 不会存在内存溢出 1.2 作用 //jvm指令 0: getstatic #20 // PrintStream ...

爱哭的毛毛虫的博客 268

【UE5】Vosk插件实战:离线语音识别与TTS朗读全流程解析

本文详细解析了如何在UE5中利用Vosk插件实现离线实时语音转文字功能。从环境配置、插件与模型准备,到核心C++组件封装与蓝图系统搭建,提供了完整的实战教程。重点解决了离线语音识别在游戏开发中的延迟、隐私和网络依赖问题,并演示了从语音识别到TTS朗读的完整交互闭环,为开发安全、实时的语音交互应用提供可靠方案。

weixin_29021291的博客 509

JVM内存奥秘:2万字深度解析,让你彻底掌握内存结构!

通过下面两个问题,理解下PC计数器使用PC寄存器存储字节码指令地址有什么用呢?为什么使用PC寄存器记录当前线程的执行地址呢?因为CPU需要不停的切换各个线程,这时候切换回来以后,就得知道接着从哪开始继续执行。JVM的字节码解释器就需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码指令。PC寄存器为什么会被设定为线程私有的?多线程在一个特定的时间段内只会执行其中某一个线程方法,CPU会不停的做任务切换,这样必然会导致经常中断或恢复。

沁禹的博客 1484

OpenManus本地部署实战:从源码编译到浏览器路径优化全解析

本文详细解析了OpenManus本地部署的全过程,从源码编译到浏览器路径优化。涵盖环境准备、源码获取、模型配置、依赖安装等关键步骤,特别针对Windows系统下的chrome.exe路径修改提供了实用解决方案,帮助开发者高效完成部署并优化性能。

weixin_28826545的博客 378

JVM(2): JVM 内存结构

www.cnblogs.com/ityouknow/p/5610232.html#3629661

jerry_player的博客 334

NE555构成多谐振荡器及三角波、正弦波的生成(附工程文件)

NE555构成多谐振荡器及三角波、正弦波的生成 续上一篇:NE555基本原理及相关公式的推导

qq_49979053的博客 5万+

SAP 零售 FMS 物料主数据(一)

SAP 零售 FMS 物料主数据(一) SAP 对于鞋服行业最新的解决方案-FMS(相当于原来的AFS+Retail);更偏向与零售; 商品主数据与原来的AFS大不相同,取消了原来的Grid的网格概念,取而代之的是变式;商品主数据维护也偏向于Retail的维护模式;事物代码也不是MM01而是MM41 /MM46; 在维护商品主数据前,需要与商品部沟通定义各种商品相关的规范如编码规则,大中小类 ,颜色库,尺码库等,此处不赘述; 创建商品需要确定哪些物料是变式物料,哪些是常规不带特性的单一物料;这决定了在创建商

weixin_45518759的博客 5061

JVM(2):内存结构、类的加载过程

一、内存结构概述 类加载器子系统 class文件进入到虚拟机后,首先进行Loading(加载)然后Linking(链接)最后进行初始化。 加载使用的加载器分为:Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)、Application ClassLoader(应用类加载器)。 连接分为:Verify(验证)、Prepare(准备)、Resolve(解析)。 内存区域 PC Registers(PC寄存器或程序计数器,.

游王子og的博客 379

双馈风机并网系统宽频振荡机理与抑制方法研究

双馈风机并网系统宽频振荡分析与抑制 摘要:本文研究了双馈风机(DFIG)接入弱电网引发的宽频振荡问题。通过建立DFIG并网系统阻抗模型,分析了锁相环带宽、电流环带宽等参数对阻抗特性的影响。研究揭示了DFIG与电网阻抗交互导致交截频率处相位差超过180°的振荡机理。提出基于锁相环优化的阻抗重塑抑制策略,采用电压补偿和陷波器改善系统稳定性。仿真结果表明,该方法能有效降低相位差约10°-168°,显著抑制宽频振荡。代码实现了阻抗建模、稳定性分析和抑制策略验证,为工程应用提供了理论依据。

huanghm88的专栏 319

深入理解JAVA虚拟机2:JVM内存结构

内存结构一览 在上一篇文章中,我们最后给出了一幅图 这幅图中,就包含了JVM的内存结构的所有组成元素,他们分别是:java堆内存、java栈、方法区、本地方法区以及pc寄存器,接下来我们就对这些区域逐一介绍。 java堆       Java堆是Java虚拟机所管理的内存中最大的一块。是线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例...

qq_37410328的博客 262

倍福--实现TCP/IP的配置

控制器为CX5120,需要和上位机做通信,选择TCP/IP的通讯方式,本文介绍TCP/IP通信的操作步骤。 目 录 软硬件版本 3 1.1. 倍福Beckhoff 3 1.1.1. 控制器硬件 3 1.1.2. 控制软件 3 1.2. 串口调试助手 3 1.2.1. TCP调试通信助手 3 授权文件 3 2.1 Lib文件 3 2.2. CAB文件 4 PLC程序编写 4 3.1. 引入TCP/IP库文件 4 3.2. Client端程序 5 3.2.1. 建立相关变量 5 3.3.2. 编写连接功能块

weixin_41883890的博客 5730

华为OD机试 C++【TLV解析】

这里的valueOffset指的是value在整串消息里的起始位置(从0开始数)。这表示tag是15(十六进制的0F),length是4,接着的8个字符是value的内容。你收到了一串由两端设备传递的TLV格式的消息,现在你需要根据这串消息生成一个对应的(tag, length, valueOffset)列表。tag是15,对应的数据长度为4,value从第3个字节开始,所以偏移量为2。第二行:一个数字n,表示我们给出的tag的数量(0 < n < 1000)。第一行:一串消息,长度不超过10000。

wtswts1232的博客 481

JVM2--JVM内存结构:类加载器、堆、栈、方法区等

一、概述 1、知识层次 内存结构、垃圾回收、性能调优 2、内存结构图 上层:入口 class文件+类加载器 编译器javac将java文件编译成字节码class文件 中层:运行时数据区 堆、方法区----共享内存 栈:java栈(虚拟机栈)、本地方法栈----线程私有 程序计数器----线程私有 下层:执行引擎:解释器、编译器(编译后端)、垃圾回收器 二...

qq_44641527的博客 322

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

JVM(2):JVM内存结构(必修。。。)

原文出处: 纯洁的微笑 +其他老师的整合 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障。 Java的内存结构: 1.程序计数器 程序计数器(Program Counte...

~ 346

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: JVM(1):Java 类的加载机制
下一篇: JVM(3):Java GC算法 垃圾收集器
架构师的清醒
博客等级 码龄14年 291粉丝 397原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值