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内存区域与内存溢出 ...
随机推荐
- [JVM] 应用诊断工具之Fastthread(在线诊断)
0 序言 背景 近期生产系统遇到了一个线程方面的问题,目前根因已定位到.现将fastthread这一诊断工具做一小结,便于以后快速使用 博主我遇到的线程问题:java.lang.OutOfMemory ...
- 编辑linux服务启动命令(app-script.sh命令编写)
#!/bin/sh# 注:这里可替换为你自己的执行程序,其他代码无需更改APP_NAME=app-biz.jar #使用说明,用来提示输入参数usage() { echo "Usage: s ...
- tomcat服务器报错
看问题 报错信息里面说 tomcat目录下conf下的aaa.xml报错 根据目录找到aaa.xml发现aaa.xml里面是空的,删除了之后就不报错了 不知道为啥这个就会报错,以前也出现过没有解决,这 ...
- TypeError: 'module' object is not callable (pytorch在进行MNIST数据集预览时出现的错误)
在使用pytorch在对MNIST数据集进行预览时,出现了TypeError: 'module' object is not callable的错误: 上报错信息图如下: 从图中可以看出,报错位置为第 ...
- MybatisPlus查询时过滤不需要的字段~
解释一下:乍一看标题可能有点懵~,其实就是想查询的时候过滤掉某些字段 例如: select name,email,password from user; --改为-> select name,e ...
- 江西财经大学第一届程序设计竞赛 G题小Q的口袋校园
题目链接:https://www.nowcoder.com/acm/contest/115/G 解题思路:题解就一份代码,贪心的思想.先按开始时间进行排序. 然后不断贪心获得happy[ j ]的最大 ...
- nginx下的proxy_pass使用
之前的文章说到了,return,rewrite的使用,以及它们的使用场景,今天再来说一种代理的使用,proxy_pass,它属于nginx下的ngx_http_proxy_module模块,没有显示的 ...
- 【Python】【OpenCV】【NumPy】图像和原始字节的转换
学习完基础的图像算法,开始接触OpenCV学习: 灰度图中,一个像素点上的灰度级需要一个字节(byte,2^8,8 bit)进行存储,此时的灰度图是二维的.而当我们需要转换为彩色图时,即三维,便会产生 ...
- 春秋云镜 - CVE-2022-28060
Victor CMS v1.0 /includes/login.php 存在sql注入 找到页面的登录框,看介绍应该是post类型的表单注入. 上sqlmap用原本的梭发现ctf的那个表是空的,换用- ...
- CentOS配置DNS服务器(BIND 9.11.*版本),并配置3种转发模式
BIND 9.11.*版本可以yum直接安装 安装BIND组件,开启DNS服务,检查状态 yum install bind bind-utils systemctl start named syste ...