Java虚拟机运行时数据区分为以下几个部分:
方法区、虚拟机栈、本地方法栈、堆、程序计数器。如下图所示:

一、程序计数器

程序计数器可看作当前线程所执行的字节码行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。Java虚拟机的多线程是通过线程轮流切换以分配处理执行时间的方式进行的,因而为了确保线程切换后能够恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程计数器独立存储,互不影响,这类内存区域称为“线程私有”内存。当线程执行Java方法时,计数器记录的时正在执行虚拟机字节码指令的地址;如果执行Native方法,则计数器值为空(Undefine)。
程序计数器时唯一一个在Java虚拟机规范中没有任何规定OutOfMemoryError情况的内存区域。

二、Java虚拟机栈

Java虚拟机栈也是线程私有的,生命周期与线程相同。Java虚拟机栈是描述Java方法执行的内存模型:每个方法执行时都会创建一个栈帧(方法运行期间的基础数据结构),方法的执行过程对应着相应的栈帧在虚拟机中从入栈到出栈的过程。我们平时提到的栈就是虚拟机栈,也称为局部变量表部分。
局部变量表存放了编译期间的各种基本数据类型、对象引用和returAdress类型。其中,double和long占两个局部变量空间(Slot),其余数据类型占据一个。局部变量表所需内存是在编译期间完成分配的,当进入一个方法时,方法在帧中分配的局部变量空间大小是完全确定的,在方法运行期间局部变量表的大小不变。
Java虚拟机栈规定了两种异常状况:

  1. 线程请求栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常。
  2. 虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存时抛出OutOfMemoryError异常。

三、本地方法栈

本地方法栈为虚拟机使用的Native方法服务,本地方法栈可根据虚拟机的具体要求自由实现。由的虚拟机(如Sun HotSpot虚拟机)直接将本地方法栈和虚拟机栈赫尔为一。
本地方法栈出现的异常为StackOverflowError和OutOfMemoryError异常。

四、Java堆

Java堆(Java Heap)是Java虚拟机内存中最大的一块。堆被所有线程共享,在虚拟机启动时创建。堆的唯一目的就是存放对象实例。一般来说,几乎所有的对象实例都在堆上分配内存。
Java堆是垃圾收集器管理的主要区域,因此又称为“GC堆”。(为什么莫名想到垃圾堆?)从内存回收角度由于收集器采用分代收集算法,故将Java堆细分为新生代,老生代;从内存分配角度将线程共享的堆划分为多个线程私有分配缓冲区。
Java堆处于物理不连接的内存空间中,只要逻辑上连续即可。如果堆中没有内存完成实例分配,且堆无法再扩展时抛出OutOfMemoryError异常。

五、方法区

方法区也是线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时候编译器编译后的代码等数据。Java虚拟机规范将方法区描述为堆的一个逻辑部分,但为与java堆进行区分,称它为Non-Heap(非堆)。由于HotSpot虚拟机用永久代来实现方法区,因而部分人习惯将方法区称为“永久代”。垃圾回收在方法区是较少出现的,这个区域内存回收主要目标是对常量池的回收和对类型的卸载。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

六、运行时常量池

运行时常量池是方法区的一部分,常量池是包含在Class文件中的一项信息,用于存放编译期生成的各种自面量和符号引用,这部分信息将在类加载后存放到方法区的运行时常量池中。一般来说,除了保存Class文件中的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。
运行时常量池与Class文件常量池相比具有动态性,并非时只有预置在Class文件中的常量池内容才能进入运行时常量池,运行期间也可以将新的常量放入池中,如String的intern()方法。当常量池无法再申请到内存时抛出OutOfMemoryError异常。

七、直接内存

直接内存并不是虚拟机运行时数据区的一部分,但这部分内存被频繁的使用,也会OutOfMemoryError异常的出现。
JDK1.4加入Input/Output类,引入基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,再通过Java堆中的DirectByteBuffer对象引用这块内存,以提高性能。它一般受到本机总内存与处理器寻址空间的限制,从而导致OutOfMemoryError异常。

本文主要参考《深入理解Java虚拟机——JVM高级特性与最佳实践》一书
另参考文章:
https://blog.csdn.net/u011116672/article/details/50994109

理解JVM之Java内存区域的更多相关文章

  1. 深入理解JVM - 1 - Java内存区域划分

    作者:梦工厂链接:https://www.jianshu.com/p/7ebbe102c1ae来源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. Java与C++之间有一堵 ...

  2. 深入理解JVM(一)--Java 内存区域

    一.  运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. Java虚拟机所管理的内存将会包括以下几个运行时数据区域:               ...

  3. 深入理解JVM(二)Java内存区域

    2.1 C.C++内存管理是由开发人员管理,而Java则交给了JVM进行自动管理 2.2 JVM运行时数据区:方法区.堆(运行时线程共享),虚拟机栈.本地方法栈.程序计数器(运行时线程隔离,私有) 1 ...

  4. JVM之Java内存区域

    JVM之Java内存区域 世界上并没有完美的程序,但我们并不因此而沮丧,因为写程序本来就是一个不断追求完美的过程. 一.JAVA内存区域 谈及JAVA虚拟机运行时数据区域就不得不祭出这张经典的图了: ...

  5. 学习jvm(一)--java内存区域

    前言 通过学习深入理解java虚拟机的教程,以及自己在网上的查询的资料,做一个对jvm学习过程中的小总结. 本文章内容首先讲解java的内存分布区域,之后讲内存的分配原则以及内存的监控工具.再下来会着 ...

  6. 深入理解JVM(6)——Java内存模型和线程

    Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM)用来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果(“即Ja ...

  7. 史上最详细JVM,Java内存区域讲解

    本人免费整理了Java高级资料,一共30G,需要自己领取:传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q 运行时数据区域 JVM载执行Jav ...

  8. JVM:Java内存区域与内存溢出异常

    Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁时间,有些区域随着虚拟机进程的启动而存在,有些区域依赖用户线程的启动和 ...

  9. 深入理解虚拟机之Java内存区域

    1 概述 对于Java程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个new 操作去写对应的delete/free操作,不容易出现内存泄漏和内存溢出问题.正是因为 ...

随机推荐

  1. 详述MSSQL服务在渗透测试中的利用 (下篇)

    part3 MSSQL写文件 步骤1 sp_makewebtask写文件 因为是`SA`权限,如果目标服务器是web服务器,我们也不用去备份了,可以直接写个一句话木马进去到web目录. 在不知道web ...

  2. ArrayList的源码分析

    在项目中经常会用到list集合来存储数据,而其中ArrayList是用的最多的的一个集合,这篇博文主要简单介绍ArrayList的源码分析,基于JDK1.7: 这里主要介绍 集合 的属性,构造器,和方 ...

  3. ASP.NET Core WebApi 项目部署到 IIS 服务器的总结

    Point: - ASP.NET Core WebApi 项目 - 发布到 IIS 服务器 1. 选择 File System 2. 输入要发布到的路径 # 其它默认,直接发布 3. 打开 IIS,添 ...

  4. cookie、session的区别

    相信你肯定经常听说cookie和Session,那你有没有好好了解这两个的区别呢?其实,不整理之前,我也是一脸懵. 为什么需要cookie和session呢?---因为Http是无状态的,web开发中 ...

  5. [视频]K8飞刀 ms15022 office漏洞演示动画

    [视频]K8飞刀 ms15022 office漏洞演示动画 https://pan.baidu.com/s/1eQnV8qQ

  6. 03-03 java 顺序语句结构,选择结构if语句

    顺序结构: /* 流程控制语句:可以控制程序的执行流程. 分类: 顺序结构 选择结构 循环结构 顺序结构: 从上往下,依次执行. */ class ShunXuJieGouDemo { public ...

  7. 线程中的读写锁ReadWriteLock

    Lock锁还有两个非常强大的类 ReadWriteLock接口实现类ReentrantReadWriteLock(非常重要的锁) 想实现 读取的时候允许多线程并发访问,写入的时候不允许. 这种效果.. ...

  8. c++中文件读取

    对于C++编译运行文件,我使用过两个编译器,一个是visual studio 2013,另外一个是devcpp,推荐使用devcpp. vs的特点是界面整洁清晰,但是需要收费,这是微软的,并且在电脑上 ...

  9. 再谈C#委托与事件

    之前写过一篇关于C#委托与事件的文章(见<C#委托和事件例析>),不过还是收到一些网友的提问.所以,今天再换另一个角度来详解一下这个问题. 一.在控制台下使用委托和事件 我们都知道,C#中 ...

  10. SSDT Hook实现内核级的进程保护

    目录 SSDT Hook效果图 SSDT简介 SSDT结构 SSDT HOOK原理 Hook前准备 如何获得SSDT中函数的地址呢 SSDT Hook流程 SSDT Hook实现进程保护 Ring3与 ...