概述:

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. 五分钟搞懂什么是B-树(全程图解)【转】

    前戏 我们大家都知道动态查找树能够提高查找效率,比如:二叉查找树,平衡二叉查找树,红黑树.他们查找效率的时间复杂度O(log2n),跟树的深度有关系,那么怎么样才能提高效率呢?当然最快捷的方式就是减少 ...

  2. Java学习笔记(4)--- 变量类型,修饰符

    1.变量类型: a.定义: 和C++差不多,就是: type identifier [ = value][, identifier [= value] ...]: type为Java数据类型.iden ...

  3. 第16讲:ODBC&JDBC简介

    一.ODBC简介 1. ODBC的概念 ①ODBC:Open DataBase Connection,即开放数据库连接 ②ODBC是一种标准,它规定了不同语言的应用程序与不同数据库服务器之间通讯的方式 ...

  4. 如何把转入成功的XXX.sql导入到自己的数据库里

    1.新建自己的mysql连接,mysql连接名随便起,如cxf  密码尽量写123456或者root,防止忘记.按照图示右键(如果想在已有的mysql连接基础上建立数据库连接直接看第二步) 2.右键名 ...

  5. Html学习之十二(CSS选择器的应用二)

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  6. (day55)七、查询优化、MTV和MCV、choices、AJAX、序列化

    目录 一.ORM查询优化 (一)only与defer (1)only (2)defer (二)select_related与prefatch_related (1)select_related (2) ...

  7. LeetCode 268. Missing Number缺失数字 (C++/Java)

    题目: Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is mi ...

  8. hasattr、getattr、setattr、delattr、反射

    目录 hasattr getattr setattr delattr 反射的应用 __import__(了解) 思考: 在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需要调用对 ...

  9. 2019 SDN上机第4次作业

    1. 解压安装OpenDayLight控制器(本次实验统一使用Beryllium版本) 配置java环境 安装OpenDayLight控制器 2. 启动并安装插件 cd distribution-ka ...

  10. weblogic 12c 安装与下载

    转   一.WebLogic的介绍     WebLogic是美国bea公司出品的一个application server,确切的说是一个基于Javaee架构的中间件,纯java开发的,最新版本Web ...