JAVA虚拟机JVM-1.内存区域

运行时数据区域

包含:程序计数器,java虚拟机栈,本地方法栈,java堆,方法区,运行时常量池。具体相关结构如下图。

区域 是否公用 相关概念 其他描述
程序计数器 线程私有 当前线程执行的字节码行号指示器 如果当前线程执行的java方法,那么计数器
java虚拟机栈 线程私有 java方法执行的线程内存模型 方法执行的时候创建的栈帧用户保存局部变量表,操作数栈,动态链接,方法出口等信息。可能抛出StackOutflowError异常。
本地方法栈 线程私有 本地方法执行的线程内存模型 本地Native方法是指可以调用操作系统底层的方法。可能抛出StackOutflowError异常。
java堆 线程共享区域 存放java的对象实例(GC回收的主要区域) JAVA堆是物理上不连续空间,但是逻辑上要连续的空间,并且大小可以进行配置,空间不足抛出OutOfMemoryError异常
方法区 线程共享区域 存放已经被虚拟机加载的类型信息,常量,静态常量,即时编译器编译后的代码缓存等数据 可以选择GC回收,也可以选择不回收。空间不足抛出OutOfMemoryError异常
运行时常量池 线程共享区域 属于方法区的一部分区域 Class文件除了标注类的版本,字段,方法,接口等描述信息外,还有就是常量池表,用于存放编译期生成的各种字面量和符号饮用。

直接内存:

NIO,引入的基于通道channel与缓冲区buffer的IO模型,可以通过Native方法直接分配堆外的内存,然后通过java堆中的DirectBuffer对象作为这块内存的引用进行操作。这样做的好处是能提高IO性能,避免了堆内存和Native堆中来回复制数据。这个内存不会收到堆内存大小的影响,但是会受到电脑内存的大小的限制。NIO相关的内容在线程章节会详细分析。

对象创建过程(虚拟机类加载机制)

对象创建过程包括:加载,验证,准备,解析,初始化。(图示为类的生命周期)

加载,验证,准备,初始化和卸载这五个阶段的顺序是确定的,解析阶段不一定,某些情况下可以在初始化之后进行解析,以便为了支持Java语言的运行时绑定特性(动态绑定或者晚期绑定)

加载:三件事

1.通过类的全限定名来获取定义此类的二进制字节流。

2.将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构。

3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

验证:

主要是为了确保Class文件的字节流中的信息符合Java规范。

验证包括:文件格式验证、元数据验证、字节码验证、符号引用验证。

准备:

准备阶段是正式为类中定义的变量分配内存并设置类初始值的阶段。

重点:

1.首先这个时候进行分配的内存仅仅包含类变量,不包含实例变量,实例变量会通过对象实例过程,在java堆中分配内存。

2.这里面设置的初始值是指“0”值。比如int a = 123;a在准备阶段的值为0,而不是123。

3.如果类字段的属性是ConstantValue,那么准备阶段就会把值初始化为指定的值。(final修饰)

解析:

解析阶段是java虚拟机将常量池内的符号引用替换为直接引用的过程。

符号引用:以一组符号来描述所引用的目标。

直接引用:可以是直接指向目标的指针,可以是相对偏移量,也可以是间接定位到目标的句柄。

解析包含:1.类或接口解析、2.字段解析、3.方法解析、4.接口方法解析。

初始化:

初始化阶段就是执行类构造器<clint>()方法的过程。

  • <clint>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句快中的语句合并产生的。收集的顺序是由语句在源文件中的出现的顺序决定的。
  • JAVA虚拟机会在执行子类的<clint>()方法之前确定执行过其父类的<clint>()方法。
  • <clint>()对于类或者接口并不是必须的,没有赋值操作或者static代码块的话编译器不会为其类生成<clint>()方法。
  • 接口和类的区别,执行接口的<clint>()方法不需要先执行父接口的<clint>()方法,只有父类的接口定义的变量被使用的时候,父类接口才会被初始化。
  • <clint>()方法在多线程的情况下会加同步锁,只会允许其中一个线程去执行这个方法。

类加载器

类加载器虽然是只是用于实现类的加载动作,但它在Java程序中起到的作用却远超类加载阶段。对于任意一个类,都必须由加载它的类加载器和这个类本身共同确立其在java虚拟机中的唯一性。

重点:判断两个类是否相等,必须保证这两个类由同一个类加载器加载。即使这两个类来源同一个Class文件,同一个虚拟机加载,如果加载器不同,那么这两个类也不相等。

双亲委派模型

从JAVA虚拟机角度看,存在两种不同的类加载器,一个是启动类加载器(C++语言实现的ClassLoader),一个是其他类加载器(java实现的java.lang.ClassLoader)。

  • 启动类加载器:负责加载<JAVA_HOME>\lib目录下的类或者被-Xbootclasspath参数指定的路径中存放的,且java可以识别的类库。
  • 扩展类加载器:负责加载<JAVA_HOME>\lib\ext目录中的类或者被java.ext.dirs系统变量指定的路径中所有的类库。
  • 应用程序加载器:负责加载用户类路径上所有的类库。

双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都有自己的父类加载器。

工作过程:如果一个类收到加载请求,首先不会加载这个类,而是把这个请求委派给父类加载器完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传到最顶层的启动加载器中,只有父类加载器反馈自己无法完成加载请求的时候,子类才会尝试自己去完成加载。

原文地址:https://www.cnblogs.com/wangb0402/p/12620661.html

时间: 2024-10-04 15:53:14

JAVA虚拟机JVM-1.内存区域的相关文章

【java】JVM的内存区域划分

学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分.在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程: 如上图所示,首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加

《深入理解Java虚拟机 JVM高级特性...》核心笔记

深入理解Java虚拟机 JVM高级特性与最佳实践(第二版) 核心笔记 JAVA 环境: JAVA虚拟机高级特性: 一:java内存区域与内存异常 一):运行数据区     1:程序计数器(Program Counter Register),也称"PC寄存器" A:用来指示需要执行哪条指令的.(在汇编语言中,CPU在得到指令之后,程序计数器便自动加1或者根据                    转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令.) B:由于在JVM中,多线程

java虚拟机--JVM

java虚拟机 是安装在计算机操作系统上的一个虚拟计算机. 专门用于处理java程序和底层操作系统的链接工作,将java程序翻译成底层的操作系统可以理解的语言. 有别于JDK.JDK是java的开发环境,是java开发人员需要的,里面除了JVM,还有一些其他的东西.JVM是小于JDK的. JVM的结构图如下图所示: 1. 类加载器:加载类文件到内存.[这里的类文件是class文件] 2. 运行数据区:1中加载的class文件,全部保存在运行数据区.java能够很好的运行,也是得益于运行数据区的管

深入理解jvm之内存区域与内存溢出

文章目录 1. Java内存区域与内存溢出异常 1.1. 运行时数据区域 1.1.1. 程序计数器 1.1.2. java虚拟机栈 1.1.3. 本地方法栈 1.1.4. Java堆(Java Heap) 1.1.5. 方法区 1.1.6. 运行时常量池 1.1.7. 直接内存 1.2. HotSpot虚拟机 1.2.1. 对象的创建 1.2.2. 对象的访问定位 1.3. OOM异常的解决思路 1.4. 参考 Java内存区域与内存溢出异常 运行时数据区域 程序计数器 当前线程所执行的字节码的

JVM的内存区域划分以及垃圾回收机制详解

在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以及ARC(自动引用计数)的内存管理方式,下方会对其进行回顾.而目前的JVM的内存回收机制则不是使用的引用计数,而是主要使用的"复制式回收"和"自适应回收". 当然除了上面是这两种算法外,还有其他是算法,下方也将会对其进行介绍.本篇博客,我们先简单聊一下JVM的区域划分,

java学习-----jvm的内存分配及运行机制

VM运行时数据区域: 根据<Java虚拟机规范(第二版)>的规定,JVM包括下列几个运行时区域: 我们思考几个问题: 1.jVM是怎么运行的? 2.JVM运行时内存是怎么分配的? 3.我们写的java代码(类,对象,方法,常量,变量等等)最终存放在哪个区? VM运行时数据区域: 1.程序计数器(program Counter Register):   是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的

Java虚拟机运行时数据区域

Java虚拟机在执行Java程序的过程中会将其管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,及创建和销毁的时间,有些区域随虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束来建立和销毁.Java虚拟机所管理的内存包括以下几个运行时数据区域,如图(图片引自网络): 1.1 程序计数器(Program Counter Register) 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器.字节码解释器就是通过改变该计数器的值来选取下一条需要执

Java虚拟机运行时数据区域划分

Java虚拟机数据运行时区域 方法区(Method Area) 存储加载的类信息,常量,静态变量,编译器编译后的代码等数据.虽然JVM规范把方法区描述为堆的一个逻辑部分,但它却有一个别名叫做Non-Heap.Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项是常量池,用于存放编译器生成的各种字面量和符号引用,包括字符串常量.JVM加载Class后把常量池中的数据放入到运行时常量池.方法区的运行时数据(包括运行时常量池)是线程共享的. 堆(Java Heap) 堆是被线程共享的

Java虚拟机JVM简单理解

Java虚拟机JVM的作用: Java源文件(.java)通过编译器编译成.class文件,.class文件通过JVM中的解释器解释成特定机器上的机器代码,从而实现Java语言的跨平台. JVM的体系结构包含三个主要的子系统和一个内存区,分别是: 垃圾回收器:用于回收堆(heap)中无引用的对象. 类装载子系统:定位及导入二进制class文件,校验被导入类的正确性,为类变量分配初始化内存,以及帮助解析符号引用. 执行引擎:执行被转载类中的方法指令. 运行时数据区:又叫做虚拟机内存或Java内存.

深入Java虚拟机JVM类加载初始化学习笔记

1. Classloader的作用,概括来说就是将编译后的class装载.加载到机器内存中,为了以后的程序的执行提供前提条件. 2. 一段程序引发的思考: 风中叶老师在他的视频中给了我们一段程序,号称是世界上所有的Java程序员都会犯的错误. 一般不假思索的结论就是,a=1,b=1.给出的原因是:a.b都是静态变量,在构造函数调用的时候已经对a和b都加1了.答案就都是1.但是运行完后答案却是a=1,b=0. 为什么呢,这3句无非就是静态变量的声明.初始化,值的变化和声明的顺序还有关系吗?Java