深入理解JVM虚拟机(一):JVM运行时数据区
概述:
JVM将内存的管理进行封装,使得开发人员不必关心内存申请、释放操作。但是在高级程序开发、复杂业务场景开发的时候,如果出现内存溢出的情况,对于开发人员而言就很难去分析出原因。所以还是很有必要去了解一下JVM是如何进行内存操作的。
基础知识普及
- 堆(Heap):是一种数据结构,数据存储方式是先进先出(FIFO-first in first out),并且以树结构进行存储,顾名思义只允许首位操作,不允许操作中间数据。堆是计算机为开发人员分配的一个存储空间,由开发人员自由支配,开发人员如果不释放,则数据一直占据在内存中,当程序结束时,系统会进行回收。堆使用的是二级缓存。
- 栈(Stack):也是一种数据结构,数据结构存储方式是先进后出(FILO-first in last out),所以只允许在队列头进行操作,不允许中间、尾部操作。栈是操作系统使用的存储区域,使用的是一级缓存。
- 进程(Progress):进程是一个独立运行的程序,它可以申请、拥有系统资源。在Linux下可以通过ps命令查看系统进程信息,Windows下通过TaskList命令查看进程信息。计算机将进程作为最小的资源分配单位。进程与进程之间不存在数据共享,所以进程之间只能进行通讯。
- 线程(Thread):线程是更小的执行单位,它不可以申请、拥有系统资源。线程的出现会使得CPU时间的利用率更高:当CPU为当前进程分配时间片的时候,当前进程会根据线程的情况再次分配。线程之间可以进行数据共享。通过此链接可以秒懂进程、线程的含义:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
- 程序计数器(Program Counter):它是用来存储下条指令存储单元。当执行一条指令时,将指令由内存取到指令寄存器中,此过程称之为“取指令”,与此同时,PC中的地址或自动加1或由转移指针给出下一条指令。这个过程就是由程序计数器来换成。
JVM管理的内存结构
JVM管理的内存结构图

介绍
- 程序计数器(Program Counter):是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器。由于JAVA虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都要有一个独立的程序计数器,各条线程之间的计数器互不影响,我们称这类区域为“线程私有”的内存。如果线程正在执行的是一个JAVA方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行Native方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
- Java虚拟机栈(JVM Stacks):它也是线程私有的,他的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会建立一个栈帧(Stack Frame,它是方法运行时的基础数据结构)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用开始到执行完成的过程,就对应有一个栈帧在虚拟机栈中入栈到出栈的过程。
- 本地方法栈(Native Method Stack):它与Java虚拟机栈的作用类似,他们之间的不用点是:Java虚拟机栈是服务于执行Java方法(即字节码);而本地方法栈是服务于执行本地方法。
- Java堆(Java Heap):它是JVM所管理的内存中最大的一块。Java堆是所有线程共享的的一块内存区域,在虚拟机启动时被创建。这个堆为一个的目的就是用来存放对象实例,几乎所有的对象实例都在这里分配内存。所以,从他的主要作用可以得出垃圾收集器会经常光顾这个区域,所以它也会被称为“GC堆”。从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆可以分为:新生代和老年代,再细致可以分为:Eden空间(伊甸园空间,最新的)、From Survivor空间(From 幸存者空间)、To Survivor空间(To 幸存者空间)[两个Survivor的存在是因为垃圾回收算法需要两个空间进行copying,这两个空间也是Eden空间到老年空间数据过渡的空间]、老年代[详情可参考:http://www.iteye.com/topic/894148]。这个堆在物理上可以不是连续的,只要逻辑上连续即可。堆的大小可以设置为可扩展,通过-Xmx和-Xms来指定堆得最大空间和最小空间,如果堆达到最大空间,并且无法继续扩展的时候,就会抛出OutOfMemoryError的异常。
- 方法区(Method Area):与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、敞亮、静态变量、即时编译器编译后的代码等数据。虽然JVM规范把方法区描述为堆得一个逻辑部分,但是它却又一个别名叫做Non-Heap(非堆),目的就是为了与Java堆区分开来。更多人把这个区域称为“永久代”(Permanent Generation)。
- 运行时常量池(Runtime Constant Pool):它是方法区的一部分。Class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区运行时常量池中释放。
- 直接内存(Direct Memory):在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道与缓冲区的IO方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了Java堆和Native堆中来回复制数据。它不会受到Java堆大小的限制。
参考:
[1] JVM内存模型
深入理解JVM虚拟机(一):JVM运行时数据区的更多相关文章
- 【JVM第三篇--运行时数据区】程序计数器、虚拟机栈、本地方法栈
写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.运行时数据区 我们在编写Java程序时,使用JVM的流程主要如下所示: 虚拟机在 ...
- JVM 专题十:运行时数据区(五)堆
1. 核心概述 1.1 堆概述 一个进程对应一个jvm实例,一个运行时数据区,又包含多个线程,这些线程共享了方法区和堆,每个线程包含了程序计数器.本地方法栈和虚拟机栈. 一个jvm实例只存在一个堆内存 ...
- JVM 专题九:运行时数据区(四)本地方法栈
1. 本地方法栈 2. 什么是本地方法栈? Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用 本地方法栈,也是线程私有的. 允许被实现成固定或者是可动态拓展的内存大小 ...
- JVM 专题八:运行时数据区(三)虚拟机栈
2.虚拟机栈 1. 概述 1.1 虚拟机栈出现背景 由于跨平台性的设计,java的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 优点是跨平台,指令集小,编译器容易实现, ...
- Jvm基础(1)-Java运行时数据区
最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来 ...
- JVM内存区域(运行时数据区)划分
前言: 我们每天都在编写Java代码,编译,执行.很多人已经知道Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文 ...
- JVM系列之四:运行时数据区
1. JVM架构图 Java虚拟机主要分为五大模块:类装载器子系统.运行时数据区.执行引擎.本地方法接口和垃圾收集模块. 2. JDK1.7内存模型-运行时数据区域 根据<Java 虚拟机规范( ...
- JVM 专题十三:运行时数据区(八)直接内存
1. 直接内存 不是虚拟机运行时数据区的一部分,也不是<Java虚拟机规范>中定义的内存区域. 直接内存是Java堆外的.直接向系统申请的内存区间. 来源于NIO,通过存在堆中的Direc ...
- JVM 专题十一:运行时数据区(六)方法区
1. 栈.堆.方法区关系交互 运行时数据区结构图: 从线程共享与否的角度来看: 2. 方法区的理解 2.1 方法区在哪里? <Java虚拟机规范>中明确说明:“尽管所有的方法区在逻辑上属于 ...
- 【JVM第四篇--运行时数据区】堆
写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.堆的概述 JVM的运行时数据区如下: 一个Java程序运行起来对应着一个进程(操 ...
随机推荐
- go构建脚本ansible分发时出现的问题总结“non-zero return code”
背景介绍: 在Jenkins服务器配置go项目发布脚本,编译完成后,使用ansible分发到部署服务器上,然后将启动项目脚本start_coachcore.sh发布到目标服务器上,执行启动,目标服务器 ...
- Linux系统配置永久明细路由
版权声明:本文为博主原创文章,支持原创,转载请附上原文出处链接和本声明. 本文链接地址:https://www.cnblogs.com/wannengachao/p/11947400.html 1.创 ...
- CentOS7设置开机自启动方式
方式一: # 在/etc/rc.d/rc.local文件中追加启动命令,该文件追加后,会随着机器自动后,自动运行文件中的命令 # vim /etc/rc.d/rc.local # 权限问题:在cent ...
- C C++ ARM X86 函数 方法 的调用约定
参考:https://bbs.pediy.com/thread-224583.htm 整理成表格方便查询 cdecl(C规范), stdcall(WinAPI默认), fastcall, ATPCS( ...
- c# WF 第1节 创建winform程序
本节内容: 1:vs的RAD 2:WinForm的创建简介 3:创建窗口与控制台程序文件的对比 4:窗口文件内容 5:winform怎么运行 6:winform的实质 1:vs的RAD 2:WinFo ...
- django DeleteView
DeleteView from django.urls import reverse, reverse_lazy from django.contrib.auth.mixins import Logi ...
- 【转】基于Bootstrap的超酷jQuery开关按钮插件
基于Bootstrap的超酷jQuery开关按钮插件
- (day51)三、ORM、路由层、版本差异、流程图
目录 一.ORM关系建立 (一)ForeignKey(一对多) (二)ManyToManyField(多对多) (三)OneToOneField(一对一) 二.django请求生命周期流程图 三.ur ...
- QTP10启动错误:Error creatingUnable to create configuration directory "C:UsersmR?ã? directory entry
安装完之后打开就一直: 百度也不知道为哈子(莫非是中文的用户名?反正我不想重装系统),真是很气人. 我就直接创建了一个临时账户,登陆进去,就可以运行了:
- ionic4之ion-sliders
<ion-content class="details_"> <img class="courimg_" src="assets/i ...