Java虚拟机的内存空间分为五个部分:

  • 方法区
  • 虚拟机栈
  • 本地方法栈
  • 程序计数器

程序计数器

定义

程序计数器是一个块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指令器。程序计数器记录的是当前线程正在执行的那一条字节指令的地址。

如果当前线程正在执行的是一个本地方法,那么程序计数器为空。

作用

程序计数器有两个作用:

  1. 字节码解释器可以通过改变程序计数器的值,从而实现堆代码执行顺序的控制,如顺序、循环;
  2. 可以线程切换的情景下,记录当前线程的运行位置。

特点

  1. 占用空间小;
  2. 线程私有;
  3. 唯一一个不会出现OutOfMemoryError的内存区域。
  4. 生命周期伴随线程的生死。

Java虚拟机栈

定义

Java虚拟机栈是描述Java方法执行线程内存模型。
在方法被执行的时候,Java虚拟机栈会同步创建一个栈帧用于存储方法运行时所需的信息,包括:

  • 局部变量表
  • 操作数栈
  • 动态连接
  • 方法出口等

特点

  1. 每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程。
  2. 经常有人把Java内存区域笼统地分为堆内存和栈内存,这样划分过于粗糙。栈通常指地就是Java虚拟机栈,或者更多情况下指的是虚拟机栈中局部变量表部分。
  3. 局部变量表存放了编译器客之的各种Java虚拟机基本数据类型、对象引用和returnAddress类型(指向了条字节码指令的地址)。
    这些数据类型在局部变量表中的存储空间以局部变量槽Slot在表示,其中64位长度的数据类型会占用两个变量槽,其余只占用一个。所以,一个变量槽的大小是32位的。局部变量表所需的内存空间在编译期间完成分配,进入方法是时,这一个方法子啊栈帧中分配的局部变量大小不会改变。
  4. 虚拟机栈会抛出两种异常:
    • 如果线程请求的栈深度大于虚拟机所允许的深度,就会抛出StackOverflowError异常;
    • 如果虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
  5. 线程私有。

注:StackOverFlowError和OutOfMemoryError的异同?
StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。
而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。

本地方法栈

定义

本地方法栈为虚拟机使用的本地方法服务,功能与虚拟机栈类似。

本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。

Java堆

定义

堆是用来存放对象实例的空间,还包括数组、字符串。
几乎所有对象实例都存放在堆中。现值类型的支持,通过即时编译技术,对象可能会分配到其他内存中。

特点

  1. 是各个线程共享的内存区域。(整个Java虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java虚拟机栈、本地方法栈都是一个线程对应一个的。)
  2. 在虚拟机启动时候创建。
  3. 垃圾回收的主要场所。
  4. 可以细分为:新生代和老年代。新生带可以分为Eden、From Survior、To Survior。所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区,用于提升分配时的效率。将堆细分知识为了更好地回收内存,或者更快地分配内存。
  5. 堆的在逻辑内存空间应当是连续的。
  6. 堆的大小可以是固定的,也可以是可扩展的。主流的虚拟机是按照可扩展的来实现的(通过参数-Xmx和-Xms设定)。如果堆中内存大小无法满足实例的分配,而且也无法扩展时,虚拟机将会抛出OutOfMemoryError异常。

方法区

定义

方法区是用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
《Java虚拟机规范》 中把方法区描述为堆的一个逻辑部分,从逻辑上可以与堆区分开。

特点

  1. 线程共享:是堆的逻辑部分,因此和堆一样是线程共享的。虚拟机中方法区唯一。
  2. 永久代:方法区的数据与需要长期存在,它是堆的逻辑部分,所以,用堆的划分方法,可以把方法区称为老年代。JDK8,HotSpot用元空间取代了永久代。
  3. 内存回收效率低,因为其中数据需要长期存在,所以一次回收只能回收少量数据。
    对方法区的内存回收目标是对常量池的回收和对类型的卸载。
  4. 虚拟机规范对方法去要求比较宽松,可以不实现垃圾回收。

运行常量池

运行常量池用于存储方法区中常量的这一部分。

在一个类中通过public static final来声明一个常量。这个类被编译后便生成Class文件,这个类的所有信息都存储在这个class文件中。

运行常量池相对于Class文件常量池具有动态性,在运行期间也可以将新的常量放入池中,例如String类的intern()方法。

当常量池无法申请到内存时会抛出OutOfMemoryError异常。

常量池中的某些常量没有被引用时就需要被回收。

直接内存

直接内存并不属于Java虚拟机的内存,但是也会被频繁地使用。

在NIO类,引入了一种基于通道与缓冲区的IO方式。它可以Native函数库直接分配堆外内存,然后通过一个存储在Java堆里的DirectByteBuffer对像作为这块内存的引用进行操作。避免了Java堆和Native堆之间的数据复制,从而提高了内存效率。

直接内存的分配不会收到Java虚拟机堆大小的限制,但是,既然是内存,还是会收到本机总内存的限制,不够的时候就会抛出OOM。

总结

  1. 线程私有的区域:程序计数器、虚拟机栈、本地方法栈。生命周期和其所属线程一样。
  2. 线程共享的区域:堆和方法区。虚拟机启动就创建,停止就销毁。
  3. 只有程序计数器不会抛出OOM异常,其他内存区域如果无法向虚拟机申请到最后的空间,都会抛出OOM。
  4. Java虚拟机内存模型中的两个栈分别是虚拟机栈和本地方法栈。两个栈的区别是:虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈式描述Java本地方法过程的内存模型。
  5. Java虚拟内存模型中的两个堆分别是Java堆和方法区。方法区属于Java堆的逻辑部分。区别是:堆中存放实例对象,而方法区存放类信息、常量、静态变量、即时编译器编译的代码数据。
  6. 堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器的主要工作区域。

深入理解Java虚拟机(一)——JVM内存模型的更多相关文章

  1. 【java虚拟机】jvm内存模型

    作者:pengjunlee原文链接:https://blog.csdn.net/pengjunlee/article/details/71909239 目录 一.运行时数据区域 1.程序计数器 2.J ...

  2. 深入理解Java虚拟机之JVM内存布局篇

    内存布局**** ​ JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...

  3. java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)

    概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...

  4. 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载

    <深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...

  5. 读书笔记-《深入理解Java虚拟机:JVM高级特性与最佳实践》

    目录 概述 第一章: 走进Java 第二章: Java内存区域与内存溢出异常 第三章: 垃圾收集器与内存分配策略 第四章: 虚拟机性能监控与故障处理 第五章: 调优案例分析与实战 第六章: 类文件结构 ...

  6. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  7. 深入理解Java虚拟机(自动内存管理机制)

    文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...

  8. 《深入理解 java 虚拟机》学习 -- 内存分配

    <深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...

  9. 《深入理解Java虚拟机:JVM高级属性与最佳实践》读书笔记(更新中)

    第一章:走进Java 概述 Java技术体系 Java发展史 Java虚拟机发展史 1996年 JDK1.0,出现Sun Classic VM HotSpot VM, 它是 Sun JDK 和 Ope ...

随机推荐

  1. Nacos服务发现源码解析

    1.Spring服务发现的统一规范 Spring将这套规范定义在Spring Cloud Common中 discovery包下面定义了服务发现的规范 核心接口:DiscoveryClient 用于服 ...

  2. 一个Wpf的开发框架

    引言 本框架使用Prism做MVVM,优点咱就不说了,主要了容器注入,消息和DI,比自己写省很多事.网上有很多标准的MVVM的使用方法,但是没有形成一个系统级的框架.本框架从登录到具体业务的使用,还有 ...

  3. python-网络安全编程第八天(实战高精度密码字典生成器)

    前言 emmmm 高精度密码字典源码 1.py import exrex import sys #url过滤处理 def host_para(host): if '://' in host: host ...

  4. Markdown进阶

    ### 事项清单 - [x] 拖地 - [x] 擦窗 - [ ] 写作业 - [ ] 交资料 效果 事项清单 [x] 拖地 [x] 擦窗 [ ] 写作业 [ ] 交资料 流程图 graph LR A[ ...

  5. Guitar Pro 7教程之添加音轨讲解

    Guitar Pro 7是当前的新版本,较之前版本GP5,GP6,不管在功能还是软件的界面上都是有了不一样的改变,最近听到很多朋友说,由于Guitar Pro 7界面与之前完全不一样,很多功能都不知道 ...

  6. 文档丢失不用怕,EasyRecovery帮你一键恢复

    我们在使用电脑的过程中,有时会因为各种原因,导致我们所写的文档丢失了.遇到这种情况,该怎么办呢? 下面,就给大家分享一下用EasyRecovery如何恢复被丢失的文档. 1.双击进入EasyRecov ...

  7. 关于GoldWave为Vegas制作音频交叉淡化特效的教程分享

    在Vegas里对音频交叉淡化的处理,是通过将两段音频交叠.调整交叠部分的音量.选取交叉淡化类型这三步来实现的,许多步骤是在音频轨道拖动音量线来实现的,操作上不够灵敏精细.其实,单就音频的交叉淡化处理, ...

  8. mac实用软件推荐 mac好用的软件

    终于入手了梦寐以求的苹果电脑,但却发现其操作系统与Windows大相径庭!不会使用怎么办?不用担心,我们可以借助软件的力量.一款实用的Mac软件不仅能够使你的工作效率显著提高,同时它还能帮助你更快地熟 ...

  9. python计算时间差

    前言 之前写代码都是看打印的初始和结束时间然后自己算间隔时间,感觉总是不方便,这不符合python的优雅简洁,于是去寻找简便之道. 方法 time模块计算时间差 import time s_time ...

  10. C语言讲义——全局变量和局部变量

    局部变量 普通的局部变量也叫动态变量,默认有个关键字叫auto,可以省略.有两种形式: 1.函数内的局部变量 2.复合语句内的局部变量:for(int i = 0; i<5; i++){-} 静 ...