概述:

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内存模型

[2] [读书笔记]深入理解java虚拟机

深入理解JVM虚拟机(一):JVM运行时数据区的更多相关文章

  1. 【JVM第三篇--运行时数据区】程序计数器、虚拟机栈、本地方法栈

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.运行时数据区 我们在编写Java程序时,使用JVM的流程主要如下所示: 虚拟机在 ...

  2. JVM 专题十:运行时数据区(五)堆

    1. 核心概述 1.1 堆概述 一个进程对应一个jvm实例,一个运行时数据区,又包含多个线程,这些线程共享了方法区和堆,每个线程包含了程序计数器.本地方法栈和虚拟机栈. 一个jvm实例只存在一个堆内存 ...

  3. JVM 专题九:运行时数据区(四)本地方法栈

    1. 本地方法栈 2. 什么是本地方法栈? Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用   本地方法栈,也是线程私有的. 允许被实现成固定或者是可动态拓展的内存大小 ...

  4. JVM 专题八:运行时数据区(三)虚拟机栈

    2.虚拟机栈 1. 概述 1.1 虚拟机栈出现背景 由于跨平台性的设计,java的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 优点是跨平台,指令集小,编译器容易实现, ...

  5. Jvm基础(1)-Java运行时数据区

    最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来 ...

  6. JVM内存区域(运行时数据区)划分

    前言: 我们每天都在编写Java代码,编译,执行.很多人已经知道Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文 ...

  7. JVM系列之四:运行时数据区

    1. JVM架构图 Java虚拟机主要分为五大模块:类装载器子系统.运行时数据区.执行引擎.本地方法接口和垃圾收集模块. 2. JDK1.7内存模型-运行时数据区域 根据<Java 虚拟机规范( ...

  8. JVM 专题十三:运行时数据区(八)直接内存

    1. 直接内存 不是虚拟机运行时数据区的一部分,也不是<Java虚拟机规范>中定义的内存区域. 直接内存是Java堆外的.直接向系统申请的内存区间. 来源于NIO,通过存在堆中的Direc ...

  9. JVM 专题十一:运行时数据区(六)方法区

    1. 栈.堆.方法区关系交互 运行时数据区结构图: 从线程共享与否的角度来看: 2. 方法区的理解 2.1 方法区在哪里? <Java虚拟机规范>中明确说明:“尽管所有的方法区在逻辑上属于 ...

  10. 【JVM第四篇--运行时数据区】堆

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.堆的概述 JVM的运行时数据区如下: 一个Java程序运行起来对应着一个进程(操 ...

随机推荐

  1. Saltstack_使用指南08_远程执行-返回程序

    1. 主机规划 salt 版本 [root@salt100 ~]# salt --version salt (Oxygen) [root@salt100 ~]# salt-minion --versi ...

  2. .net core使用百度webupload上传图片

    后端代码: /// <summary> /// 图片上传,上传路径: "/Uploads/Images/" + folder + "/" + sav ...

  3. Linux命令: cat

    -s  连续多个空行显示为一个空行. -n 给每一行前显示行号. -b 只给非空行前显示行号. -E  在每行后显示一个$ cat f - g  把文件f的内容.STDIN.文件g的内容连接起来 .

  4. Pwnable-fd

    打开Ubuntu输入ssh fd@pwnable.kr -p2222,连接之后输入密码guest 之后就是ls -l看看里面的文件和权限,fd.fd.c.flag 看看fd.c的源码 #include ...

  5. python27期尚哥讲TCP:

    TCP:传输控制协议(使用情况多于udp) 稳定:保证数据一定能收到 相对UDP会慢一点 web服务器一般都使用TCP(银行转账,稳定比快要重要)TCP通信模型: 在通信之前,必须先等待建立链接 TC ...

  6. 从游击队到正规军:马蜂窝旅游网的IM系统架构演进之路

    本文引用自马蜂窝公众号,由马蜂窝技术团队原创分享. 一.引言 今天,越来越多的用户被马蜂窝持续积累的笔记.攻略.嗡嗡等优质的分享内容所吸引,在这里激发了去旅行的热情,同时也拉动了马蜂窝交易的增长.在帮 ...

  7. SpringBoot整合log4j2导入新的依赖出现jar冲突解决

    1.问题复现: 之前在SpringBoot中配置整合了log4j2,今天在pom文件中,导入新的依赖(依赖如下)之后, <dependency> <groupId>com.gi ...

  8. vs2017离线包下载安装并且不占用C盘空间使用教程

    安装vs2017,前提是你的环境是.NET4.6,VS2017在下载好安装程序安装的时候,会根据你选择的功能模块来下载所需要的安装程序,微软.安卓和苹果等平台的SDK.模拟器和第三方扩展功能等会在用户 ...

  9. 一个简单的利用 WebClient 异步下载的示例(二)

    继上一篇 一个简单的利用 WebClient 异步下载的示例(一) 后,我想把核心的处理提取出来,成 SkyWebClient,如下: 1. SkyWebClient 该构造函数中 downloadC ...

  10. Java使用路径通配符加载Resource与profiles配置使用

    序言 Spring提供了一种强大的Ant模式通配符匹配,能从一个路径匹配一批资源. Ant路径通配符 Ant路径通配符支持“?”.“*”.“**”,注意通配符匹配不包括目录分隔符“/”: “?”:匹配 ...