运行时数据区中包含哪些区域?哪些线程共享?哪些线程独享?

简介: 运行时数据区中包含哪些区域?哪些线程共享?哪些线程独享?【⭐⭐⭐⭐⭐】Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK 1.8 和之前的版本略有不同,下面会介绍到。

image.png image.png 区别就是 1.8有一个元数据区替代方法区了。

image.png 那么,Java 8 中 PermGen 为什么被移出 HotSpot JVM 了?我总结了两个主要原因(详见:JEP 122: Remove the Permanent Generation):


由于 PermGen 内存经常会溢出,引发恼人的 java.lang.OutOfMemoryError: PermGen,因此 JVM 的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的 OOM

移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。

根据上面的各种原因,PermGen 最终被移除,方法区移至 Metaspace,字符串常量移至 Java Heap。

image.png 程序计数器


程序计数器(Program Counter Register)是一块较小的内存空间,由于JVM可以并发执行线程,因此会存在线程之间的切换,而这个时候就程序计数器会记录下当前程序执行到的位置,以便在其他线程执行完毕后,恢复现场继续执行。


JVM会为每个线程分配一个程序计数器,与线程的生命周期相同。


如果线程正在执行的是应该Java方法,这个计数器记录的是正在执行虚拟机字节码指令的地址。


如果正在执行的是Native方法,计数器的值则为空(undefined)


注意:程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。


本地方法栈


Java虚拟机栈是调用Java方法;本地方法栈是调用本地native方法,可以认为是通过 JNI (Java Native Interface) 直接调用本地 C/C++ 库,不受JVM控制。


方法执行完毕后相应的栈帧也会出栈并释放内存空间,也会出现 StackOverFlowError 和 OutOfMemoryError 两种错误。

image.png 虚拟机栈


虚拟机栈 描述的是 Java 方法执行的内存模型:


每个方法在执行的同时都会创建一个栈帧(Stack Frame,是方法运行时的基础数据结构)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。


虚拟机栈是每个线程独有的,随着线程的创建而存在,线程结束而死亡。


在虚拟机栈内存不够的时候会OutOfMemoryError,在线程运行中需要更大的虚拟机栈时会出现StackOverFlowError。

image.png Java 堆


Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。


堆是垃圾收集器管理的主要区域,又称为“GC堆”,可以说是Java虚拟机管理的内存中最大的一块。


现在的虚拟机(包括HotSpot VM)都是采用分代回收算法。在分代回收的思想中, 把堆分为:新生代+老年代+永久代(1.8没有了); 新生代 又分为 Eden + From Survivor + To Survivor区。

image.png 方法区


方法区(Method Area)与 Java 堆一样,是所有线程共享的内存区域。


方法区用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等。


方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。


方法区比较重要的一部分是运行时常量池(Runtime Constant Pool),为什么叫运行时常量池呢?是因为运行期间可能会把新的常量放入池中,比如说常见的String的intern()方法。


元空间


1.8就把方法区改用元空间了。类的元信息被存储在元空间中。元空间没有使用堆内存,而是与堆不相连的本地内存区域。所以,理论上系统可以使用的内存有多大,元空间就有多大,所以不会出现永久代存在时的内存溢出问题。


可以通过 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 来指定元空间的大小。

image.png

目录
相关文章
|
1月前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
18天前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
41 3
|
30天前
|
消息中间件 设计模式 安全
多线程魔法:揭秘一个JVM中如何同时运行多个消费者
【8月更文挑战第22天】在Java虚拟机(JVM)中探索多消费者模式,此模式解耦生产与消费过程,提升系统性能。通过`ExecutorService`和`BlockingQueue`构建含2个生产者及4个消费者的系统,实现实时消息处理。多消费者模式虽增强处理能力,但也引入线程安全与资源竞争等挑战,需谨慎设计以确保高效稳定运行。
59 2
|
30天前
|
缓存 Java 容器
多线程环境中的虚假共享是什么?
【8月更文挑战第21天】
24 0
|
2月前
|
安全 开发者
LabVIEW程序退出后线程仍在运行问题
LabVIEW程序退出后线程仍在运行问题
35 2
|
2月前
|
Rust 安全 程序员
Rust与C++的区别及使用问题之Rust解决多线程下的共享的问题如何解决
Rust与C++的区别及使用问题之Rust解决多线程下的共享的问题如何解决
|
3月前
|
Java 程序员
Java多线程编程是指在一个进程中创建并运行多个线程,每个线程执行不同的任务,并行地工作,以达到提高效率的目的
【6月更文挑战第18天】Java多线程提升效率,通过synchronized关键字、Lock接口和原子变量实现同步互斥。synchronized控制共享资源访问,基于对象内置锁。Lock接口提供更灵活的锁管理,需手动解锁。原子变量类(如AtomicInteger)支持无锁的原子操作,减少性能影响。
42 3
|
3月前
|
Java
【技术解码】Java线程的五味人生:新建、就绪、运行、阻塞与死亡的哲学解读!
【6月更文挑战第19天】Java线程生命周期如同人生旅程,经历新建、就绪、运行、阻塞至死亡五阶段。从`new Thread()`的诞生到`start()`的蓄势待发,再到`run()`的全力以赴,线程在代码中奔跑。阻塞时面临挑战,等待资源释放,最终通过`join()`或中断结束生命。线程的每个状态转变,都是编程世界与哲思的交汇点。
27 1
|
2月前
|
存储 安全 Java
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
49 0
|
2月前
|
存储 SQL 安全
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
35 0