走进JVM【二】理解JVM内存区域

引言

对于C++程序员,内存分配与回收的处理一直是令人头疼的问题。Java由于自身的自动内存管理机制,使得管理内存变得非常轻松,不容易出现内存泄漏,溢出的问题。

不容易不代表不会出现问题,一旦内存泄漏或溢出的情况发生,调试起来会变得非常困难。这就要求我们对虚拟机的内存区域有深入的理解。最终能够判断内存方面的异常发生时,具体在JVM中的位置。

内存区域

image

JVM运行时,首先需要类加载器(ClassLoader) 加载所需类的字节码,加载完毕交由执行引擎执行,执行过程中需要一段空间来存储数据(类比CPU与主存)。这段内存空间的分配和释放过程正是我们所关心的,称为运行时数据区

对于CS相关从业者,深入理解操作系统的内存的层次结构,分配与垃圾收集过程都是大有裨益的。同理,欲定位内存问题的出现区域,必须剖析运行时数据区

运行时数据区

如上图所示,运行时数据区包括:程序计数器(即PC寄存器),Java 虚拟机栈(VM Stack),Java 堆(Heap),方法区(Method Area),本地方法栈(Native Method Stack)。下面带领大家深入理解各个数据区域

JVM实际上就是一台虚拟的计算机,目的是为了实现"一次编译,处处执行"。所以,在理解运行时数据区时,完全可以与操作系统系统 内存,寄存器类比学习。

程序计数器

每条虚拟机中的线程都有自己的寄存器,称之为程序计数器(PC)。为了保证线程之间的独立性,因而PC内的空间是线程私有的。

  • 线程私有只能本线程访问的区域,其他线程无权访问。

程序计数器的作用

虚拟机中的多线程通过线程轮转调度,为每条线程分配时间片来实现并发执行。同一时刻,处理机只能执行一条线程。当切换到另外一条线程时,若不保存当前未执行完线程的执行位置,下次处理机再执行这条线程时,又要重新开始执行。这种情况显然是不能容忍的。

引入程序计数器的目的,就是为了记录线程的执行情况,便于下次切换后进行线程恢复

程序计数器的机制

如何记录线程的执行情况? 其实也并不复杂,只需要记录正在执行的虚拟机字节码指令的地址。如果运行的是Native(本地)方法,计数器的值为Undefined

程序计数器是唯一没有OutOfMemoryError异常的区域。

Java 虚拟机栈

每个Java方法执行时,需要分配内存空间来存储局部变量表操作数栈动态链接方法出口等信息。将这部分内存称之为栈帧(Stack Frame)。虚拟机栈用于存储栈帧,是Java方法执行的内存模型

显然我们需要为每个执行的方法分配栈空间,因此Java虚拟机栈也是线程私有的。

虚拟机栈的作用

虚拟机栈记录Java方法执行的过程。每个方法开始执行时,为之创建一个栈帧记录信息;方法执行到完成的过程,对应栈帧在虚拟机栈中入栈到出栈的过程

image

局部变量表

局部变量表是栈帧中的重要部分。存放编译期定义的基本数据类型对象引用(相当于对象地址),及returnAddress类型(字节码指令地址)。

局部变量表空间在编译期间分配,执行方法的过程中不会改变其大小。

异常

  1. 当线程请求的栈深度大于所允许的深度,抛出StackOverflowError异常。
  2. 长度不够时,虚拟机栈可进行动态扩展,申请内存。若无法申请到足够的内存,抛出OutOfMemoryError异常。

本地方法栈

本地方法栈与虚拟机栈类似,区别是虚拟机栈记录执行的Java方法,本地方法栈则记录Native方法。

本地方法栈同样会抛出StackOverflowErrorOutOfMemoryError异常。

Java 堆

Java堆用于存储对象实例,为所有对象分配内存空间

所有对象实例都要在堆上分配空间,因此Java堆是所有线程共享区域。对象的生命周期结束后,Java堆还要负责内存回收,因此Java堆也常被称之为GC堆(Garbage Collected Heap)。

内存模型

从内存回收的角度,Java堆可以分为新生代(Young Generation)与老生代(Old Generation)。这种划分的方式,是为了更好的回收内存(老生代内存会被优先回收)。

image

如图,新生代还可以分为Eden空间From Survivor空间To Survivor空间

永久代(Permanent Generation)用于存储静态类型数据,与垃圾收集器关系不大。

注意:本图展示的是JVM堆的内存模型,JVM堆内存包括Java堆区域 和 永久代区域。因此,永久代不属于Java堆

异常

Java堆同样可扩展(-Xmx与-Xms参数)。若堆中内存已无法为对象实例分配且无法再扩展,抛出OutOfMemoryError异常。

方法区

方法区存储类信息常量静态变量等数据,是线程共享的区域。为与Java堆区分,方法区还有一个别名Non-Heap(非堆)。

方法区≠永久代

方法区就是永久代?并非如此。

HotSpot虚拟机选择用永久代来实现方法区,从而省去了为方法区编写内存管理代码的工作。这只是一种实现方式,其他虚拟机(BEA JRockit,IBM J9)都不存在永久代这一概念。

通过永久代来实现方法区容易造成内存溢出,未来也可能会被替代。

在虚拟机规范中,方法区的实现没有明确的规定,因此不能将方法区等同于永久代。

异常

当方法区无法满足内存分配的需要时,抛出OutOfMemoryError异常。

运行时常量池

运行时常量池(Runtime Constant Pool)用于存放编译期生成的各种字面量和符号引用。

运行时常量池具备动态性,使得运行期间也可将新的常量放入池中。例如String类的intern() 方法。

package intern;public class Main1 {public static void main(String[] args) {String s0= "I'm coding";   String s1=new String("I'm coding");   String s2=new String("I'm coding");   system.out.println( s0==s1 );  System.out.println( s0==s1.intern());   s2=s2.intern();  System.out.println( s0==s2 );   }
}

输出结果

false
true
true

本例中,s0直接保存在常量池,s1与s2的对象实例存储在Java堆中。==直接比较对象的hashCode,因此第一行输出false。s1.intern()方法返回s1在常量池中的引用,没有则创建。
s1存放的字符串已经在常量池中存在,直接返回s0的引用,第二行输出true
同理,s2接收了s2.intern()的返回值,字符串值与s0相同,第三行输出true

运行时常量池是方法区的一部分,因此受方法区内存的限制。当无法申请到内存时,抛出OutOfMemoryError异常。

总结

对于JVM的内存管理, 最重要的还是与OS内存管理知识进行类比以及结合实践来学习。理解JVM内存区域的目的也是为了在工程中出现内存相关异常时能够准确的定位所在区域,及时处理。

后续我们将在本文的基础上来理解对象的创建过程以及OutOfMemoryError异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql一对多_mysql一对多查询合并多的一方的数据。

有时候会有这样一个需求,查询的一条记录需要包含另一个表的多条记录,并且让多条记录成为一个字段组成最终的一条记录。比较难描述,看例子吧。创建一个产品表:create table product(proId int(10),proName varchar(50))创建一个成分…

Matlab矩阵、元胞数组的合并拼接

矩阵合并拼接 1.横向拼接 [a,b] [a b]均可 例1 >> amagic(3)a 8 1 63 5 74 9 2>> brand(3)b 0.6324 0.5469 0.15760.0975 0.9575 0.97060.2785 0.9649 0.9572>> c[a,b]c 8.0000 1.0000 6.0000 0.632…

Matlab拆分矩阵/Matlab如何分割大矩阵(mat2cell函数)

dim1Dist分割后矩阵行数组成的向量,dimNDist指的是分割后矩阵列数组成的向量 例有100*200的矩阵A >> Arand(100,200); >> bmat2cell(A,[30 40 30],[100 70 30])b 33 cell 数组{30100 double} {3070 double} {3030 double}{40100 double} {40…

分布式系统部署、监控与进程管理的几重境界

陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice t.sina.com.cn/giantchen 陈硕关于分布式系统的系列文章:http://blog.csdn.net/Solstice/category/802325.aspx 本作品采用“Creative Commons 署名-非商业性使用-禁止演绎 3.0 Unported 许可协议(cc by-nc-nd)”…

.net core mvc初级教程(六)

一、创建movie的视图 二、对cinema、movie视图添加‘添加信息’的操作 一、创建movie的视图 在views文件夹下添加Movie文件夹,在这个文件夹下添加Index.cshtml视图,为什么添加Index.cshtml这个名字的视图,可以看看我们写的MovieController控制…

apache camel_发掘Apache Camel的力量

apache camel最近几年,ESB软件越来越受欢迎。 如果大多数人通常知道什么是ESB,那么他们很少会清楚地了解这种体系结构的不同组件的确切作用。 例如,Apache ServiceMix由三个主要组件组成:Apache Karaf(OSGI容器&#…

角反射器的功能及应用

雷达反射器又名角反射器,它是通过金属板材根椐不同用途做成的不同规格的雷达波反射器。当雷达电磁波扫描到角反射后,电磁波会在金属角上产生折射放大,产生很强的回波信号,在雷达的屏幕上出现很强的回波目标。由于角反射器有极强的…

mysql卸载权限不够_Linu下启动MySQL结果显示:env: /etc/init.d/mysql:权限不够怎么解决?...

展开全部Linu下启动MySQL结果显示:env: /etc/init.d/mysql: 是脚本执行的问题解决办法:依次e69da5e887aa3231313335323631343130323136353331333365633936执行下面的命令(执行失败的话,检查路径是否正确):cp /etc/init.d/mysql /e…

GDAL/ORG之Python获取与安装

GDAL(Geospatial Data Abstraction Library)是一个的开源栅格空间数据读取/转换库。其中还有一系列命令行工具来进行数据转换和处理。而ORG项目是GDAL的一个分支,功能与GDAL类似,但其提供对矢量数据的支持。 也就是说,可以用ORG的库来读取、处…

Firewall配置

一、安装firewall #yum install -y firewalld firewall-config 二、启动并设置开机自启动# systemctl start firewalld# systemctl enable firewalld# systemctl stop firewalld# systemctl disable firewalld 三、firewall配置# firewall-config 防火墙图形配置界面# firewall…

网页cookie是什么?

Cookie 是用户访问的网站创建的文件,存储在用户电脑的硬盘中,用于保存浏览信息,例如您的网站偏好设置或个人资料信息。网站依靠Cookie辨认用户行踪,了解用户感兴趣内容,收集与用户有关的信息。用户访问查询网页上操作信…

使用基于微服务的流架构更好地进行大规模的复杂事件处理(第1部分)

基于微服务的流架构与开源规则引擎相结合,使实时业务规则变得容易 这篇文章旨在详细说明我将OSS业务规则引擎与Kafka风格的现代流消息传递系统集成在一起的项目。 该项目的目标(即众所周知的复杂事件处理(CEP))旨在实…

chown r mysql ._chown -R 用户名:组名 ./ 及 chown用法介绍

当我们在不通过yum(CentOS)、apt-get(Ubuntu)来安装MySQL的时候,通常执行以下命令来改变目录的拥有者:[rootlocalhost ~]# chown -R mysql:mysql ./这两个mysql谁是用户名谁是用户组呢?见chown详解。chown将指定文件的拥有者改为指定的用户或…

c语言abs和fabs的区别是什么?

abs是整数取绝对值,定义在stdlib.h头文件中。而fabs是指浮点数取绝对值,定义在math.h头文件中。 函数原型 int abs(int x) double fabs(double x)

Linux下编译GDAL

一、准备工作 从官网下载GDAL、PROJ.4和GEOS,将其存放在/home/liml/Work/3rdPart目录并解压,如下图所示。下载地址请自行Google。注:使用的系统是CentOS6.4 X64版本,其他的Linux系统都是一样的。 接下来检查系统中是否安装了开发…

PS提示错误1解决办法

重装电脑系统后,PS打不开了,提示错误1.在网上搜索,很多网友说要卸载重装。控制面板看不到ps,于是下载了Adobe卸载工具(点击链接下载),但是这个程序识别不了安装的ps.最后通过以下办法解决。 1.…

如何为你的博客园添加到百度统计

1.打开百度统计的地址 https://tongji.baidu.com/web/welcome/login?castkLTE%3D 2.注册,打开网址后,右面有注册按钮,点击注册 选择站长版,点击去 填写自己的注册信息 3.填完之后,登录进去,在管理标签下有…

mysql 左连接 重复_mysql左连接重复行

我正在设计一个类似于4个表格的字典数据库wordswordid | lemmasenseswordid | synsetidsynsetssynsetid | definitionsamplessynsetid | sample所以我使用下面的查询来获取所有意义定义和样本if(isset($searchterm)){echo "".$searchterm."";// QUERY TO F…

osgi java_使普通的旧Java OSGi兼容

osgi java尽管OSGi在Java世界中越来越流行,但仍有许多Java应用程序和库尚未设计成可在OSGi中使用。 有时您可能需要在OSGi环境中运行这样的代码,或者是因为您想利用OSGi本身提供的好处,或者因为您只需要此特定环境提供的某些功能。 通常&…

Matlab如何求离散点的导数

1.通过差分估算 已知同维度的x和y序列&#xff0c;则可使用diff(y)./diff(x)来估算。设x为n维向量&#xff0c;Dxdiff(x) 计算向量x的向前差分&#xff0c;DX(i)X(i1)-X(i)&#xff0c;0<i<n。 例一 y[7.86 7.84 7.82 7.77 7.72 7.68 7.61 7.51 7.42 7.33 7.21 7.07 6…