Java内存区域

本文介绍了Java内存模型的基本概念,详细阐述了程序计数器、Java虚拟机栈、本地方法栈、Java堆和方法区等运行时数据区域的功能及特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、题外话:

 当我们编写一个.java源文件后,然后敲击javac命令,会将该文件编译成.class文件。当然,如果是在eclipse上开发,它会默认帮助我们进行编译,所以才会给我们提示错误(仅仅是编译期间能发现的错误)。然后该.class文件可以由加载器加载到jvm中执行。大概过程如下,而今天需要探讨的是下图中的RunTime Data Areas区域,即java内存模型。


2、概述:

  Java内存模型,往往是指Java程序在运行时内存的模型,而Java代码是运行在Java虚拟机之上的,由Java虚拟机通过解释执行(解释器)或编译执行(即时编译器)来完成,故Java内存模型,也就是指Java虚拟机的运行时内存模型。在Java中,由于有虚拟机自动内存的管理,故不需要为每一个new操作去写delete/free代码,也不容易出现内存泄露和溢出的问题。不过也正因为如此,一旦出现内存泄漏和溢出方面的问题,必须对java虚拟机是怎么使用内存的有一定的了解才好排查问题。

3、运行时数据区域:

  Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间。根据《Java虚拟机规范(Java SE 7版)》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如下图所示:


  3.1 程序计数器

   程序计数器(PC),通俗理解就是一个指向当前所执行字节码所在地址的指针,通过它的值来选取下一条需要执行的字节码指令,例如分支,循环,跳转等等。该计数器内存区域为线程私有的内存,即每个线程都有自己的计数器,各线程之间计数器互不影响,独立存储。

   如果线程正在执行一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值为(Undefined)。此区域内存是唯一一个没有规定任何OutOfMemoryError情况的区域。

  3.2 java虚拟机栈

    该栈为线程私有,每执行一个方法的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链表、方法出口信息等。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。


    局部变量表中存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(可能是一个指向 一个代表对象起始地址的引用,也可能是代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。其中,long和double占用两个局部变量空间(slot),其余数据类型一个。局部变量空间大小在编译期间就已经确定。运行期间不再改变。

   java虚拟机栈有两种异常:如果线程请求的栈深度大于虚拟机所允许的深度,就会抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够内存,就会抛出OutOfMemoryError异常。

  3.3 本地方法栈

    该栈与虚拟机栈类似,它们之间的区别是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机执行使用到的Native方法服务。

  3.4 Java堆

    Java堆是Java虚拟机管理的最大的一块内存,是被线程共享的一块内存区域在虚拟机启动时创建。此内存的唯一目的就是存放对象实例,几乎所有的对象实例和数组都要在此分配。但是随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优先技术将会导致一些微妙的变化发生,所有对象都分配在堆上也渐渐变得不那么"绝对"了。

   Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为"GC堆"。从内存回收角度,Java堆被分为新生代和老年代;这样划分的好处是为了更快的回收内存;从内存分配角度,Java堆可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB);这样划分的好处是为了更快的分配内存。如果在堆中没有内存完成实例分配,会抛出OutOfMemoryError异常。

 3.5 方法区

    方法区在是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、   常量以及编译器编译后的代码等。在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。在JVM规范中,没有强制要求方法区必须实现垃圾回收,对它的限制也比较宽松。该区域会抛出OutOfMemoryError异常。

参考资料《深入理解Java虚拟机》





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值