JVM运行时数据区域(五大内存区划分--堆Heap、虚拟机栈VM Stack、程序计数器Programming Counter、方法区Method Area、本地方法栈Native Method)

我是蚊子码农,本次将为大家介绍JVM的五大内存区划分。

一、主题概括

对于操作系统来说,Java虚拟机只是一个普通应用程序,所以操作系统会给它分配一块内存。
为了更方便地构建Java程序结构和管理内存,JVM将这块内存又细分成了5个部分。
分别是堆区Heap、虚拟机栈VM Stack、本地方法栈Native Method Stack、方法区Method Area和程序计数器Programming Counter。
本文主要介绍这些内存的功能、异常,也会提及外界功能的交互。

二、功能介绍

本节内容,介绍每个内存的主要功能。

  1. 程序计数器PC:辅助执行引擎,执行下一条字节码指令。
  2. 虚拟机栈VM Stack:帮助Java方法的执行。
  3. 本地方法栈NM Stack:帮助本地方法的执行。【本地方法,即C、C++方法】
  4. 堆区Heap:管理几乎所有对象实例和数组。
  5. 方法区Method Area:存储类定义信息。【即,class文件中的信息】

三、程序计数器Programming Counter

  1. 作用:完成“程序控制”这一工作,实现分支、循环、跳转、异常处理、线程恢复等基础功能;
  2. 工作内容:通过改变值,得到下一条执行的字节码指令,从而使执行引擎能够正确执行指令;
  3. 线程私有:原因在下面;
  4. 异常:无(未定义);

在JVM中,多线程的实现,是通过线程的轮流切换、分配处理器执行时间实现的。为了每个线程在切换后,能够恢复到正确的执行位置,为每个线程都定义了一个程序计数器。各个线程之间的程序计数器,互不影响,独立存储。
由于这块内存的功能比较确定,也没有修改内容的操作,出现异常的可能性基本为0,因此JVM未定义其异常。

四、虚拟机栈VM Stack(Virtual Machine Stack):

  1. 作用:支持Java方法的执行。
  2. 工作内容:通过使用“栈帧”存储Java方法的信息,来执行线程中的Java方法的执行。
  3. 线程私有:原因在下面。
  4. 异常:有2个,可能会出现栈溢出StackOverflowError,或者内存溢出OutOfMemoryError错误。

一个线程,可能会调用多个Java方法。这时候,我们需要描述这个线程是如何执行Java方法的。
栈具有先进后出的特性,恰好调用方法这个行为吻合,因此,JVM使用虚拟机栈,来存储“栈帧”这个数据结构,用来支持Java方法的执行。
一个“栈帧”,可以理解为一个Java方法,存储了Java方法执行的信息,比如局部变量表、操作数栈、方法出口等。
由于每一个线程,所需要执行的Java方法都不一样,所以需要采用不同的虚拟机栈,用来支持不同线程的Java方法的执行。
从线程的角度出发,如果一个线程需要执行新的Java方法,那么虚拟机栈就需要增加新的栈帧,也就是栈的深度要+1。
然而,由于虚拟机栈的深度有所限制,假如一个线程执行了太多的方法,超过了栈深度,就会报错“StackOverflowError”,这个错误,常在一个问题规模特别大的递归函数里出现,比如计算一个n=一千万的斐波那契额数列。
从内存的角度出发,如果机器分配给JVM的内存已经满了(即全部都是有用的数据),并且,JVM向本地机器申请内存被拒绝。在这种情况下,如果虚拟机栈创建新的栈帧,则会出现内存溢出错误,即“OutOfMemoryError”。

五、本地方法栈NM Stack(Native Method Stack):

本地方法栈和虚拟机栈基本一致,比较明显的区别是,本地方法栈用于支持本地方法的执行。
本地方法,即用C、C++编写的方法。这些方法,通过JNI(Java Native Interface)调用。
由此,本地方法栈也是线程私有的,通常也会出现内存溢出OutOfMemoryError错误,或栈溢出StackOverflowError错误。
当然,由于JVM规范对这块内存的实现没有特殊要求,有一些实际的JVM实现,会把本地方法栈,和Java虚拟机栈合二为一,以方便内存的管理。

六、堆区Heap:

  1. 作用:管理几乎所有对象实例、数组,支持垃圾回收的工作、支持对象实例的创建。
  2. 工作内容:存储着对象实例、数组,以供其它操作。
  3. 线程共享:允许所有线程的访问。
  4. 异常:内存溢出OutOfMemoryError。

从Java应用程序的角度出发,Java应用一定会new一些对象。这些new出来的对象,在内存里就体现为堆区的一些数据。
抽象来看,内存的管理,有3步,分配内存、操作和回收内存。
JVM提供了垃圾回收机制,其绝大部分工作,都是在堆里实现的。
在class文件加载时,方法区Method Area中会存储一个类的抽象数据结构,但是,这只是一个结构,没有办法实际使用。
当new操作后,JVM会在堆区创建一个对象实例,这时候才可以使用。
所有的线程,操作的对象都是从Heap中拿到的。
当系统内存不足,无法实例化对象时,就会报错内存溢出。

七、方法区Method Area:

  1. 作用:存储静态变量,存储类信息【类信息,常规情况下就是静态变量,除非是对字符串进行某些改变】
  2. 工作内容:支持对象实例化。
  3. 线程共享:
  4. 异常:内存溢出OutOfMemoryError

在class文件加载后,类的定义信息会存储在这里。
过去,通常会把方法区、堆区合二为一,使得垃圾回收机制实现起来更加简单。
然而,常规情况下,一个类定义信息并不大,而且通常一个类的卸载也很少出现,所以认为不值得回收,所以垃圾回收机制在这里很少调用。
类定义信息虽然不大,但是在一个服务器里,这一小块内存也是比较关键的,所以又优化了垃圾回收机制。在比较现代的JVM中,通常会将方法区放在本地内存中,以减少方法区产生错误的可能。

八、结语

我是蚊子码农,如有补充或者疑问,欢迎在评论区留言。个人的知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值