深入理解Java虚拟机(一)——JVM内存模型
Java虚拟机的内存空间分为五个部分:
- 方法区
- 堆
- 虚拟机栈
- 本地方法栈
- 程序计数器

程序计数器
定义
程序计数器是一个块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指令器。程序计数器记录的是当前线程正在执行的那一条字节指令的地址。
如果当前线程正在执行的是一个本地方法,那么程序计数器为空。
作用
程序计数器有两个作用:
- 字节码解释器可以通过改变程序计数器的值,从而实现堆代码执行顺序的控制,如顺序、循环;
- 可以线程切换的情景下,记录当前线程的运行位置。
特点
- 占用空间小;
- 线程私有;
- 唯一一个不会出现OutOfMemoryError的内存区域。
- 生命周期伴随线程的生死。
Java虚拟机栈
定义
Java虚拟机栈是描述Java方法执行线程内存模型。
在方法被执行的时候,Java虚拟机栈会同步创建一个栈帧用于存储方法运行时所需的信息,包括:
- 局部变量表
- 操作数栈
- 动态连接
- 方法出口等
特点
- 每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程。
- 经常有人把Java内存区域笼统地分为堆内存和栈内存,这样划分过于粗糙。栈通常指地就是Java虚拟机栈,或者更多情况下指的是虚拟机栈中局部变量表部分。
- 局部变量表存放了编译器客之的各种Java虚拟机基本数据类型、对象引用和returnAddress类型(指向了条字节码指令的地址)。
这些数据类型在局部变量表中的存储空间以局部变量槽Slot在表示,其中64位长度的数据类型会占用两个变量槽,其余只占用一个。所以,一个变量槽的大小是32位的。局部变量表所需的内存空间在编译期间完成分配,进入方法是时,这一个方法子啊栈帧中分配的局部变量大小不会改变。 - 虚拟机栈会抛出两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的深度,就会抛出StackOverflowError异常;
- 如果虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
- 线程私有。
注:StackOverFlowError和OutOfMemoryError的异同?
StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。
而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。
本地方法栈
定义
本地方法栈为虚拟机使用的本地方法服务,功能与虚拟机栈类似。
本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。
Java堆
定义
堆是用来存放对象实例的空间,还包括数组、字符串。
几乎所有对象实例都存放在堆中。现值类型的支持,通过即时编译技术,对象可能会分配到其他内存中。
特点
- 是各个线程共享的内存区域。(整个Java虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java虚拟机栈、本地方法栈都是一个线程对应一个的。)
- 在虚拟机启动时候创建。
- 垃圾回收的主要场所。
- 可以细分为:新生代和老年代。新生带可以分为Eden、From Survior、To Survior。所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区,用于提升分配时的效率。将堆细分知识为了更好地回收内存,或者更快地分配内存。
- 堆的在逻辑内存空间应当是连续的。
- 堆的大小可以是固定的,也可以是可扩展的。主流的虚拟机是按照可扩展的来实现的(通过参数-Xmx和-Xms设定)。如果堆中内存大小无法满足实例的分配,而且也无法扩展时,虚拟机将会抛出OutOfMemoryError异常。
方法区
定义
方法区是用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
《Java虚拟机规范》 中把方法区描述为堆的一个逻辑部分,从逻辑上可以与堆区分开。
特点
- 线程共享:是堆的逻辑部分,因此和堆一样是线程共享的。虚拟机中方法区唯一。
- 永久代:方法区的数据与需要长期存在,它是堆的逻辑部分,所以,用堆的划分方法,可以把方法区称为老年代。JDK8,HotSpot用元空间取代了永久代。
- 内存回收效率低,因为其中数据需要长期存在,所以一次回收只能回收少量数据。
对方法区的内存回收目标是对常量池的回收和对类型的卸载。 - 虚拟机规范对方法去要求比较宽松,可以不实现垃圾回收。
运行常量池
运行常量池用于存储方法区中常量的这一部分。
在一个类中通过public static final来声明一个常量。这个类被编译后便生成Class文件,这个类的所有信息都存储在这个class文件中。
运行常量池相对于Class文件常量池具有动态性,在运行期间也可以将新的常量放入池中,例如String类的intern()方法。
当常量池无法申请到内存时会抛出OutOfMemoryError异常。
常量池中的某些常量没有被引用时就需要被回收。
直接内存
直接内存并不属于Java虚拟机的内存,但是也会被频繁地使用。
在NIO类,引入了一种基于通道与缓冲区的IO方式。它可以Native函数库直接分配堆外内存,然后通过一个存储在Java堆里的DirectByteBuffer对像作为这块内存的引用进行操作。避免了Java堆和Native堆之间的数据复制,从而提高了内存效率。
直接内存的分配不会收到Java虚拟机堆大小的限制,但是,既然是内存,还是会收到本机总内存的限制,不够的时候就会抛出OOM。
总结
- 线程私有的区域:程序计数器、虚拟机栈、本地方法栈。生命周期和其所属线程一样。
- 线程共享的区域:堆和方法区。虚拟机启动就创建,停止就销毁。
- 只有程序计数器不会抛出OOM异常,其他内存区域如果无法向虚拟机申请到最后的空间,都会抛出OOM。
- Java虚拟机内存模型中的两个栈分别是虚拟机栈和本地方法栈。两个栈的区别是:虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈式描述Java本地方法过程的内存模型。
- Java虚拟内存模型中的两个堆分别是Java堆和方法区。方法区属于Java堆的逻辑部分。区别是:堆中存放实例对象,而方法区存放类信息、常量、静态变量、即时编译器编译的代码数据。
- 堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器的主要工作区域。
深入理解Java虚拟机(一)——JVM内存模型的更多相关文章
- 【java虚拟机】jvm内存模型
作者:pengjunlee原文链接:https://blog.csdn.net/pengjunlee/article/details/71909239 目录 一.运行时数据区域 1.程序计数器 2.J ...
- 深入理解Java虚拟机之JVM内存布局篇
内存布局**** JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...
- java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)
概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载
<深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...
- 读书笔记-《深入理解Java虚拟机:JVM高级特性与最佳实践》
目录 概述 第一章: 走进Java 第二章: Java内存区域与内存溢出异常 第三章: 垃圾收集器与内存分配策略 第四章: 虚拟机性能监控与故障处理 第五章: 调优案例分析与实战 第六章: 类文件结构 ...
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
- 深入理解Java虚拟机(自动内存管理机制)
文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...
- 《深入理解 java 虚拟机》学习 -- 内存分配
<深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...
- 《深入理解Java虚拟机:JVM高级属性与最佳实践》读书笔记(更新中)
第一章:走进Java 概述 Java技术体系 Java发展史 Java虚拟机发展史 1996年 JDK1.0,出现Sun Classic VM HotSpot VM, 它是 Sun JDK 和 Ope ...
随机推荐
- ubuntu掉电出现检查文件系统的问题
修改: /etc/default/rcS FSCKFIX=no 为 FSCKFIX=yes 出现这个情况的原因是硬件时钟偏移了 显示上次挂载根目录在未来时间. 写于: 2013年11月28日 更新于: ...
- C#设计模式-原型模式(Prototype Pattern)
引言 在软件开发过程中,我们习惯使用new来创建对象.但是当我们创建一个实例的过程很昂贵或者很复杂,并且需要创建多个这样的类的实例时.如果仍然用new操作符去创建这样的类的实例,会导致内存中多分配一个 ...
- no appropriate service handler found,修改数据库的最大连接数,默认150
no appropriate service handler found,频繁进行数据操作的时候,会出现这种错误.例如,当我读取excel时,一次读取好多数据,这个时候需要修改数据库的最大连接数 se ...
- kali 系列学习02 - 被动扫描
被动扫描是指目标无法察觉的情况下进行信息收集,注意有经验的渗透工程师会在信息收集上花费整个测试过程一半以上的时间,信息量太大,需要自动化的信息收集工具. 一.借鉴<kali linux2 网络渗 ...
- 如何用pdfFactory新建打印机并设置属性
今天我们来讲一讲,在pdfFactory中如何去修改PDF文件打印页面的页边距.页面大小.页面清晰度等属性参数. pdfFactory是一款Windows平台上的虚拟打印机,在没有打印机可以安装的情况 ...
- 苹果电脑下载器Folx有没有自动下载功能
苹果电脑下载器Folx提供了多项自动化任务功能,供用户更好地利用电脑的空闲时间,减少自己直接参与下载的时间,从而提升下载效率. 接下来,小编将重点介绍Folx自动化工作中的任务完成后的自动化工作.自动 ...
- Trie树总结
Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交 ...
- 【模板】【P3402】可持久化并查集
(题面来自洛谷) 题目描述 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...
- java Base64算法
Base64算法并不是加密算法,他的出现是为了解决ASCII码在传输过程中可能出现乱码的问题.Base64是网络上最常见的用于传输8bit字节码的可读性编码算法之一.可读性编码算法不是为了保护数据的安 ...
- [题解] 洛谷 P3393 逃离僵尸岛
题目TP门 很明显是一个最短路,但是如何建图才是关键. 对于每一个不可遍历到的点,可以向外扩散,找到危险城市. 若是对于每一个这样的城市进行搜索,时间复杂度就为\(O(n^2)\),显然过不了.不妨把 ...