概述:

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. cluster集群基本概念

    cluster集群种类: 1,LB(Load Balance)负载均衡集群: 弱点:当横向扩展到一定机器后,发现在怎么横向加机器也没有效果的时候,瓶颈就卡在分发的服务器上了,也就是LB机器上了,如何解 ...

  2. [PHP] error_reporting(0)可以屏蔽Fatal error错误

    按照以前的印象,error_reporting(0)屏蔽不了php的Fatal error级别的错误.但是今天我遇到了一个问题才发现,它竟然可以屏蔽任何错误,包括Fatal error,浏览器会看不到 ...

  3. Jmeter之命令行生成HTML报告

    其实每次使用jemter.bat文件启动JMeter时,命令行窗口都会提示我们不要使用GUI窗口进行测试,除非是进行调试脚本 使用命令行生成结果也很测试报告也很简单 jmeter -n -t [jmx ...

  4. ACM-后序遍历(简单方法和正规方法)

    1.后序遍历简单方法 /**二叉树遍历一般有三种方法:前序,中序,后序.*其中前序遍历u顺序为:根->左子树->右子树,在此定义一种新的遍历方法:根->右子树->左子u树*使用 ...

  5. eclipse创建java项目

    工欲善其事必先利其器,记录一下eclipse怎么创建java项目 0x01:选择工作空间 打开eclipse出现的下面第一个界面,选择java project的空座区间,简单的说就是把你创建的java ...

  6. day66_10_10,vue项目环境搭建

    一.下载. 首先去官网查看网址. 下载vue环境之前需要先下载node,使用应用商城npm下载,可以将其下载源改成cnpm: """ node ~~ python:nod ...

  7. 对象锁和class锁

    对象锁:就是这个锁属于这个类的对象实例,可以通过为类中的非静态方法加synchronized关键字 或者使用 synchronized(this) 代码块,为程序加对象锁. Class锁:就是这个锁属 ...

  8. 三台三层交换机OSPF多区域划分动态路由实验

    一.实验拓扑 二.实验步骤 1.给主机设置IP,网关:给交换机划分VLAN,给VLAN划分端口,给VLAN设置IP 2.启用OSPF.宣告网段(network 网络地址 反掩码 区域名     其中0 ...

  9. 无聊系列 - C#中一些常用类型与java的类型对应关系

    昨天在那个.NET转java群里,看到一位朋友在问C#的int 对应java的哪个对象,就心血来潮,打算写一下C#中一些基础性的东西,在java中怎么找. 1. 基础值类型 如:int,long,do ...

  10. 物联网架构成长之路(42)-直播流媒体入门(RTMP篇)

    1. 安装RTMP流媒体服务器 以前其实我是利用Nginx-RTMP-module搭建过RTMP流媒体服务器,并实现了鉴权功能.参考https://www.cnblogs.com/wunaozai/p ...