运行时数据区
运行时数据区
官方解读
Chapter 2. The Structure of the Java Virtual Machine (oracle.com) The Java Virtual Machine defines various run-time data areas that are used during execution of a program. Some of these data areas are created on Java Virtual Machine start-up and are destroyed only when the Java Virtual Machine exits. Other data areas are per thread. Per-thread data areas are created when a thread is created and destroyed when the thread exits.
方法区
基本概念
JVM 只有一个方法区,且是被所有 JVM 线程共享的,方法区的生命周期是与 JVM 互相绑定的。方法区拥有以下特点:
- 方法区是各个线程共享的内存区域,在虚拟机启动时创建
- 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器变异后的代码等数据
- 对染 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却又有一个别名叫做 Non-Heap(非堆),目的是与 Java 堆区分开来
- 当方法区无法满足内存分配需求时,讲会抛出 OOM 异常
- 方法区在 JDK8 中就是 Metaspace 元空间,在 JDK6 和 7 中式 Perm Space
- 运行时常量池属于方法区的一部分在方法区中进行分配
- 方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。例如,同时有两个线程都访问方法区中的同一个类,而这个类还没有被装入 JVM ,那么只允许一个线程去装载它,而其它线程会被阻塞
运行时常量池
A run-time constant pool is a per-class or per-interface run-time representation of the
constant_pool
table in aclass
file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
堆
基本概念
JVM 只有一个堆,且是被所有 JVM 线程共享的,类和数组等主要在堆中进行内存分配,堆的生命周期同样是与 JVM 互相绑定的。堆拥有以下特点:
- 堆是 Java 虚拟机锁管理内存中最大的一块,在虚拟机启动时创建,被所有线程共享
- Java 对象实例以及数组都在堆上分配
- 当堆无法满足内存分配需求时,将抛出 OOM 异常
虚拟机栈
- 虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个 Java 线程的运行状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的、独有的,随着线程的创建而创建
- 每一个线程执行的方法,为该栈中的栈帧,即每个方法的执行操作会对应一个栈帧
- 调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出
以下异常情况与 Java 虚拟机堆栈相关联:
- 栈帧数超过栈深会抛出
StackOverflowError
异常,如:无中断递归、无返回栈帧压入等 - 如果 Java 虚拟机堆栈可以动态扩展,并且尝试扩展但没有足够的内存可用于实现扩展,或者如果没有足够的内存可用于为新线程创建初始 Java 虚拟机堆栈,则 Java 虚拟机将抛出
OutOfMemoryError
异常
栈帧
- 每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间
- 每个栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、动态链接(Dynamic Linking)、方法返回地址(Return Address)和附加信息
理解栈帧
通过 javap
指令得到反编译的字节码文件中一个方法的流程代表一个栈帧,一个栈帧中存放了 jvm 的指令
public static int calc(int, int);
Code:
0: iconst_3 // 将int类型常量3压入操作数栈
1: istore_0 // 将int类型值存入局部变量0
2: iload_0 // 从局部变量0中装载int类型值到操作数栈
3: iload_1 // 从局部变量1中装载int类型值到操作数栈
4: iadd // 执行int类型的加法
5: istore_2 // 将int类型值存入局部变量2
6: iload_2 // 从局部变量2中装载int类型值
7: ireturn // 从方法中返回int类型的数据
程序计数器
基本概念
一个 JVM 进程中有多个线程正在执行,而线程中的内容是否能够拥有执行权,是根据 CPU 调度来的。
加入线程 A 正在执行到某个地方,突然失去了 CPU 的执行权,切换到了线程 B,然后当线程 A 再获得 CPU 执行权的时候,就需要通过线程中维护的一个变量来记录线程执行到哪个位置。程序计数器具有如下特点:
- 程序计数器占用的内存空间很小,由于 Java 虚拟机的多线程是通过线程轮流切换的,并分配处理器执行时间的方式来实现的,在任意时刻,一个处理器只会执行一条线程中的指令。因此,为了线程切换后能够恢复到正确的位置,每条线程需要有一个独立的程序计数器(线程私有)
- 如果线程正在执行 Java 方法,则计数器记录的是正在执行的虚拟机字节码指令的地址
- 如果正在执行的是 Native 方法,则这个计数器为空
本地方法栈
基本概念
如果当前线程执行的方法是 Native 雷晓宁的,这些方法就会在本地方法栈中执行,主要通过 C/C++ 来执行。
相关文章
- JVM运行时数据区-方法区
- matlab运行结果图片如何保存_应对数据丢失最简单的方法
- JVM-运行时数据区概述及线程
- django 前后端不分离,多个模板有相同的数据渲染,用 inclusion_tag 少写代码
- Spark入门实战系列–4.Spark运行架构详解大数据
- 大数据处理分析的工具介绍详解大数据
- mongodb 运行时禁用 Transparent Huge Pages详解大数据
- 返回的数据MySQL存储游标返回结果的实现(mysql存储游标)
- MySQL数据库程序设计:实现数据存储更高效率(mysql数据库程序设计)
- MySQL:让数据简化管理(mysql取首字母)
- MySQL 运行查询:揭秘每天的超级数据(mysql查询天数据)
- Redis实现高效数据更新,让你的应用飞速运行!(redis数据更新数据)
- SQL Server杀锁:拯救数据运行死锁的救星(sqlserver杀锁)
- Linux系统数据丢失,如何救回?(linux数据丢失)
- 库C语言程序从Oracle数据库取数据的实现(c 获取oracle数据)
- 命令行运行MySQL实现数据导入(cmd运行mysql导入)
- Oracle职位职责支持企业数据服务器的稳定运行(oracle主要工作职责)
- 大数据时代Oracle中索引的增删指导(oracle中索引加减)
- Redis集群实现数据分片提高运行效率(redis 集群数据分片)
- 重启后Redis如何保留数据(redis重启后数据保存)
- 从Redis运行逻辑看数据存储技术(redis运行逻辑)
- 如果SQL2000装在用户数据所在的盘,请检查SQL运行用户的磁盘配额是否足够