Java虚拟机——内存区域及内存溢出异常
一、Java内存区域
1、概述
对于java程序员来说,在虚拟机的自动内存管理机制的帮助下,不需要为每一个new操作去写delete/free代码,而且不容易出现内存泄漏和内存溢出问题。但是把内存控制的权利交给虚拟机管理,一旦出现内存泄漏和溢出的问题,不了解虚拟机是怎样使用内存的,那排查错误将会成为一项异常艰难的工作。
2、运行时数据区域
2.1、程序计数器
程序计数器(Program Counter Register)是一块较小的内存空间,他的作用可以看做事当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基本功能都需要依赖这个计数器来完成。
由于java虚拟机的多线程是通过线程轮流切换并分配处理执行时间的方式实现的,所以每条线程都需要有一个独立的程序计数器,因此程序计数器是线程私有的内存区域。
如果线程正在执行的是一个java方法,则计数器记录的是正在执行的虚拟机字节码执行的地址,如果正在执行的是Native方法,则计数器为空(Undefined)。
2.2、Java虚拟机栈
与程序计数器一样,java虚拟机栈也是线程私有的,他的生命周期于线程相同。虚拟机栈主要描述的java方法执行的内存模型,每个方法被执行的时候会同时创建一个栈帧用于存储局部表量表、操作栈、动态链接、方法出口等信息。方法被调用时就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
1、局部表量表:是存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型)和returnAddress类型。
注意:其中64位长度的long和double数据类型会占用2个局部变量空间,其余的数据类型只占用1个。
a、reference类型:他不等于对象本身,根据不同的虚拟机实现,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置。
b、returnAddress类型:指向了一条字节码指令的地址。
2.3、本地方法栈
本地方法栈和虚拟机栈的作用是非常相似的,区别不过是虚拟机执行java方法服务,也就是字节码服务,而本地方法栈是为虚拟机使用的Native方法服务。
2.4、java堆
java堆是java虚拟机所管理的内存中最大的一块。是被所有线程共享的内存区域,在虚拟机启动时创建。存放的是对象实例,几乎所有的对象实例都在这里分配内存。
java堆是垃圾收集器管理的主要区域,因此很多时候也称为“GC堆”。
java堆细分为:新生代和老年代,再细致一点有Eden空间、From Survivor空间、To Survivor空间。
2.5、方法区
方法区与java堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
2.6、运行时常量池
是方法去的一部分。Class文件中除了有类的版本、字段、方法、接口等信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用,这些内容都会放在类加载后存放到方法区的运行时常量池中。
注意:运行时常量池相对于Class文件常量池的另一个重要特征就是具备动态性,java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中的常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。
2.7、直接内存
直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规则中定义的内存区域,但是这部分内存也是被频繁使用的。
3、对象访问
在java语言中,对象访问是如何进行的?对象访问也会涉及java栈、java堆、方法区这三个重要的内存区域。列如:
Object object = new Object();
假如这行代码出现在方法体中,“Object object”这部分的语义会反映到java栈的本地变量表中,作为一个reference类型数据出现。而“new Object()”的语义会反映到java堆中,形成一块存储了object类型所有实例数据值的结构化内存,根据具体类型以及虚拟机实现的对象内存布局的不同,这块内存的长度是不固定的。
对象访问的两种方式:句柄和直接指针。
使用句柄方式:Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。
使用直接指针方式:java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference中直接存储的就是对象地址。
二、内存溢出异常
1、Java堆溢出
java堆用于存储对象实例,只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量到达最大堆的容量限制后产生内存溢出异常。
2、虚拟机栈和本地方法栈溢出
在HotSpot虚拟机中并不是区分虚拟机栈和本地方法栈,因此对于HotSpot来说,-Xoss参数虽然存在,但实际上是无效的,栈容量只有-Xss参数设定。在java虚拟机规范中描述了两种异常:
a、如果线程请求的长深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常;
b、如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
注:在单线程下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。
3、运行时常量池溢出
要向运行时常量池中添加内容,最简单的做法是使用String.intern()这个Native方法。作用:如果池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加但常量池中,并且返回此String对象的应用。由于常量池分配在方法区内,可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而限制其中常量池的容量。
4、方法区溢出
方法区用于存放Class的相关信息,方法区溢出一般是运行时产生大量的类去填满方法区,就会出现溢出。
方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾回收器回收掉,判断条件是非常苛刻的。即使是同一个类文件,被不同的加载器加载时也会视为不同的类。
5、本机直接内存溢出
DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与java堆的最大值(-Xmx)一样。列如:使用DirectByteBuffer分配内存也会抛出内存溢出异常,但他抛出异常时并没有真正的向操作系统申请分配内存,而是通过计算得知内存无法分配,于是手动抛出异常,真正申请分配内存的方法是unsafe.allocateMemory()。
Java虚拟机——内存区域及内存溢出异常的更多相关文章
- 《深入理解Java虚拟机》Java内存区域与内存溢出异常
注:“蓝色加粗字体”为书本原语 先来一张JVM运行时数据区域图,再接下来一一分析各区域功能: 程序计数器 程序计数器(program Counter Register)是一块较小的内存空间,它可以 ...
- 深入理解java虚拟机系列(一):java内存区域与内存溢出异常
文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...
- 《深入理解Java虚拟机》-----第2章 Java内存区域与内存溢出异常
2.1 概述 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任 ...
- 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常
第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域
- 深入了解Java虚拟机(1)java内存区域与内存溢出异常
java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...
- 《深入理解Java虚拟机》笔记--第二章、Java内存区域与内存溢出异常
Java程序员把内存的控制权交给了Java虚拟机.在Java虚拟机内存管理机制的帮助下,程序员不再需要为每一个new操作写对应的delete/free代码,而且不容易出现内存泄露和溢出. 虚拟机在执行 ...
- 深入理解java虚拟机---->java内存区域与内存溢出异常
2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...
- 《深入理解 Java 虚拟机》读书笔记:Java 内存区域与内存溢出异常
前言 最近开始看这本书,记得前段时间拿起这本书的时候,心情是相当沉重的!当时的剧本是这样的-- 内景.家里 - 下午 我(画外):唉,有点无聊啊!(偶然撇过书架)这么多书得看到什么时候啊,要不要拿一本 ...
- [深入理解JVM虚拟机]第2章-Java内存区域与内存溢出异常
2.0引-Java内存区域中,栈内存和堆内存分别装什么,为什么? 栈:解决程序的运行问题,即程序如何执行,或者说如何处理数据. 堆:解决的是数据存储的问题,即数据怎么放,放在哪儿. 参考链接https ...
- 虚拟机--第二章java内存区域与内存溢出异常--(抄书)
这是本人阅读周志明老师的<深入理解Java虚拟机>第二版抄写的,有很多省略,不适合直接阅读,需要阅读请出门左转淘宝,右转京东,支持周老师(侵权请联系删除) 第二章java内存区域与内存溢出 ...
随机推荐
- 常见速率协议的CDR带宽情况
100G PAM4 4MHZ 802.3/OIF-CEI 50G PAM4 4MHZ 802.3/OIF-CEI 28G PAM4 4MHZ 802.3/OIF-CEI 28G PAM4 4MHZ 8 ...
- [ICPC2014WF]Sensor Network
题目描述 A wireless sensor network consists of autonomous sensors scattered in an environment where they ...
- 向mq写消息
1.基础版本 import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.comm ...
- Python给exe添加以管理员运行的属性
需求 有些应用每次启动都需要用管理员权限运行,比如Python注入dll时,编辑器或cmd就需要以管理员权限运行,不然注入就会失败. 这篇文章用编程怎么修改配置实现打开某个软件都是使用管理员运行,就不 ...
- MySQL 事务的基础知识
事务的基础知识 1. 数据库事务概述 事务是数据库区别于文件系统的重要特性之一,当我们有了事务就会让数据库中的数据始终保持 一致性,同时我们还能通过事务的机制 恢复到某个时间地点的数据,这样可以保证已 ...
- 手写spring的ioc的流程截图(笔记-1)
spring ioc是什么? IoC 容器是 Spring 的核心,也可以称为 Spring 容器.Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期. S ...
- IDEA将JavaFx打包为exe Win+Mac+Linux多平台分发等等
IDEA将JavaFx打包为exe Win+Mac+Linux多平台分发等等 前面介绍到了用packr打包javafx17为exe多平台分发,比较复杂,这篇则介绍用idea直接打包exe,比较简单,但 ...
- 面试官:请列举 Spring 的事务会失效的场景
在日常工作中,如果对 Spring 的事务管理功能使用不当,则会造成 Spring 事务不生效的问题.而针对 Spring 事务不生效的问题,也是在跳槽面试中被问的比较频繁的一个问题. 今天,我们就一 ...
- 文心一言 VS 讯飞星火 VS chatgpt (37)-- 算法导论5.4 1题
一.一个屋子里必须要有多少人,才能让某人和你生日相同的概率至少为1/2? 必须要有多少人,才能让至少两个人生日为 7月 4 日的概率大于 1/2? 文心一言: 一个屋子里必须要有多少人,才能让某人和你 ...
- Java 获取Excel中的表单控件
Excel中可通过[开发工具]菜单栏下插入表单控件,如文本框.单选按钮.复选框.组合框等等,插入后的控件可执行设置控件格式,如大小.是否锁定.位置.可选文字.数据源区域.单元格链接等.当Excel中已 ...