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. day05-类型转换和变量

    1.类型转换概念 java是强类型语言,所以有些运算的时候,需要用到类型转换 类型转换原则:低-->高,byte,short,char-->int-->long-->float ...

  2. Spark闭包 | driver & executor程序代码执行

    Spark中的闭包 闭包的作用可以理解为:函数可以访问函数外部定义的变量,但是函数内部对该变量进行的修改,在函数外是不可见的,即对函数外源变量不会产生影响. 其实,在学习Spark时,一个比较难理解的 ...

  3. Java的比较器Comparable与Comparator

    在Java中有两个比较器:Comparable.Comparator 对于Integer.Double等等类型,可以直接对他们进行比较,因为已经实现了比较的方式,然而在平时常常会面临需要对集合进行排序 ...

  4. 巧妙使用MathType快速编写数学函数公式

    在我们日常的工作与学习中,你是否也会遇到过无法在电脑中编写数学函数公式的情况呢? 简单的数学函数公式或许经过我们不懈的努力也可以成功的编写,不过这会耽误我们大把的时间. 想象一下,假如你的老板急着催你 ...

  5. FL studio系列教程(九):FL Studio中如何排列编曲

    在FL Studio水果音乐制作软件播放列表中可以对制作的样本进行编排,除此之外,播放列表中排列的对象被叫做剪辑.在其中可以排列以下剪辑. 1.样本剪辑:样本剪辑包含了编排好的插件乐器音符数据. 2. ...

  6. Jmeter(一)发送http请求

    Jmeter中发请求的步骤 1.添加线程组 2.添加http消息头管理器 3.添加http请求 一.线程组: 1.添加路径: 2.字段解释 ①线程数(Number of Threads): : 设置发 ...

  7. python debug调试

    ------------恢复内容开始------------ 一.debug 1.step over f8(单步调试) 2.进入到下一个断点 3.运行到指定行 4.进入到对应的代码行,(和单步调试配合 ...

  8. 再论<? extends T>和<? super T>

    参考: https://www.cnblogs.com/drizzlewithwind/p/6100164.html Java 泛型 <? super T> 中 super 怎么 理解?与 ...

  9. 一万三千字的HashMap面试必问知识点详解

    目录 概论 Hasmap 的继承关系 hashmap 的原理 解决Hash冲突的方法 开放定址法 再哈希法 链地址法 建立公共溢出区 hashmap 最终的形态 Hashmap 的返回值 HashMa ...

  10. LaTex中的中文处理方法

    相关代码与注释: 显示效果: