JVM 运行时数据区详解( 总结修订了其他博客, 侵删 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/j550341130/article/details/82152054

总览

JVM 运行时数据区主要有以下几类

  1. JVM栈 (Java Virtual Machine Stacks)
  2. 堆内存 (Heap Memory)
  3. 方法区 (Method Area)
  4. 本地方法栈 (Native Method Stacks)
  5. 程序计数器 (Program Counter (PC) Register)

引用https://blog.csdn.net/zhangqiluGrubby/article/details/59110906中的一张图:
这里写图片描述
在这几类中, JVM栈是每个线程均分配一个, 堆内存/方法区/本地方法栈是所有线程共享, 它们的运作关系大体如下图( 画工太烂 ):
这里写图片描述


各类数据区详细分析

1. JVM栈 (Java Virtual Machine Stacks)

在介绍 JVM栈 之前, 先了解一下 栈帧 概念
栈帧:一个栈帧随着一个方法的调用开始而创建, 这个方法调用完成而销毁. 栈帧内存放者方法中的局部变量, 操作数栈等数据.

而 JVM栈 就是一个栈帧的集合, JVM栈只对栈帧进行存储, 压栈和出栈操作.
这里写图片描述

当线程执行一个方法时, 就会随之创建一个对应的栈帧, 并将建立的栈帧压栈. 当方法执行完毕之后, 便会将栈帧出栈. 对于所有的程序设计语言来说, 栈这部分空间对程序员来说是不透明的.

栈内存的大小可以有两种设置, 固定值和根据线程需要动态增长.
在JVM栈这个数据区可能会发生抛出两种错误.
1. StackOverflowError 出现在栈内存设置成固定值的时候, 当程序执行需要的栈内存超过设定的固定值会抛出这个错误.
2. OutOfMemoryError 出现在栈内存设置成动态增长的时候, 当JVM尝试申请的内存大小超过了其可用内存时会抛出这个错误.

总结
1. 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象, 对象都存放在堆区中).
2. 每个栈中的数据(基础数据类型和对象引用)都是私有的, 其他栈不能访问.
3. 栈分为3个部分:基本类型变量, 执行环境上下文, 操作指令区(存放操作指令).
4. 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配.
5. 当在一段代码块定义一个变量时, Java就在栈中为这个变量分配内存空间, 当该变量退出该作用域后, Java会自动释放掉为该变量所分配的内存空间, 该内存空间可以立即被另作他用.

2. 堆内存 (Heap Memory)

堆数据区是用来存放对象和数组(特殊的对象). 堆内存由多个线程共享. 堆内存随着JVM启动而创建. 众所周知, Java中有一个很好的特性就是自动垃圾回收. 垃圾回收就操作这个数据区来回收对象进而释放内存. 如果堆内存剩余的内存不足以满足于对象创建, JVM会抛出OutOfMemoryError错误.

总结
1. 存储的全部是对象, 每个对象包含一个与之对应的class信息(class信息用于获取操作指令).
2. jvm只有一个堆区(heap)被所有线程共享, 堆区中不存放基本类型和对象引用, 只存放对象本身.
3. 堆的优势是可以动态地分配内存大小, 生存期也不必事先告诉编译器, 因为它是在运行时动态分配内存的, Java的垃圾收集器会自动收走这些不再使用的数据.
4. 缺点是, 由于要在运行时动态分配内存, 存取速度较慢.

3. 方法区 (Method Area)

方法区与堆一样, 是被线程共享的区域. 在方法区中, 存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等.

方法区中存有一个非常重要的部分: 运行时常量池, 它是每一个类或接口的常量池的运行时表示形式, 在类和接口被加载到JVM后, 对应的运行时常量池就被创建出来.

4. 本地方法栈 (Native Method Stacks)

本地方法栈是JVM实现了native方法调用支持的数据区, Java官方对于本地方法的定义为methods written in a language other than the Java programming language, 就是使用非Java语言实现的方法, 一般为C或者C++, 因此这个栈也有着C栈这一称号. 一个不支持本地方法执行的JVM没有必要实现这个数据区域.

本地方法栈基本和JVM栈一样, 其大小也是可以设置为固定值或者动态增加, 因此也会对应抛出StackOverflowError和OutOfMemoryError错误.

5. 程序计数器 (Program Counter (PC) Register)

在通用的计算机体系中, 程序计数器用来记录当前正在执行的指令, 在JVM中也是如此. 程序计数器是线程私有, 所以当一个新的线程创建时, 程序计数器也会创建. 由于Java是支持多线程, Java中的程序计数器用来记录当前线程中正在执行的指令. 如果当前正在执行的方法是本地方法, 那么此刻程序计数器的值为undefined. 注意这个区域是唯一一个不抛出OutOfMemoryError的运行时数据区.


参考引用:
1. https://blog.csdn.net/zhangqiluGrubby/article/details/59110906
2. https://blog.csdn.net/qq_31997407/article/details/79675371

猜你喜欢

转载自blog.csdn.net/j550341130/article/details/82152054
今日推荐