Java 运行时的内存分配


不同于C和C++的自主分配内存,java是采用虚拟机的自动内存管理。
运行时的数据区可以分成五种:程序计数器,虚拟机栈,本地方法栈,堆和方法区。其中虚拟机栈,本地方法栈,程序计数器是被线程共享;方法区和堆是被线程隔离

在这里插入图片描述


程序计数器(Program Counter Register)

这是一块较小的内存区域,可以看作是当前线程所执行的字节码的行号指示器。
程序计数器的作用:

  • 通过改变计数器的值来选取下一条需要执行的指令,如分支,循环,跳转,异常处理,线程恢复等
  • 每个线程都有一个独立的程序计数器,记录着程序执行到的位置,从而保证,经过线程切换后依然能找到正确的执行位置。

如果线程线程执行的是一个java方法,计数器记录的是正在执行的虚拟机字节码的指令地址;
如果线程执行的是一个本地方法,计数器记录的值为空。

Java虚拟机栈(VM Stack)

虚拟机栈描述的是java方法执行的线程内存模型,也是线程私有的。每个方法被执行的时候,java虚拟机会同步创建一个栈帧, 用于存储局部变量表,操作数栈,动态链接,方法出口。每个方法别调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中从出栈到入栈的过程
在这里插入图片描述
局部变量表:

  • 基本数据类型:boolean, byte, char, short, int, float, double, long
  • 对象引用: 可能是指向对象起始地址的指针
  • returnAddress: 指向了一条字节码指令的地址
    局部变量所需要的内存空间在编译期间完成分配,当进入一个方法时,局部变量需要的内存空间是完全可以确定的,在方法运行的期间,局部变量表的大小不会改变。

本地方法栈(Native Method Stack)

使用方法同java虚拟机栈,只不过它是处理本地方法,而虚拟机栈处理java方法。对象实例在堆中创建,并且“几乎”所有的对象都在这里分配内存。

Java堆(Heap)

java堆是虚拟机中管理内存最大的一块,而且是被所有线程共享的,在虚拟机启动时创建。从分配内存的角度看,所有线程共享的java堆中,可以划分出多个线程私有的分配缓冲区(TLAB Thread Local Allocation Buffer)提升对象分配时的效率(更好的回收内存,更快的分配内存)。但所有的方法都不会改变堆的特性,储存的是对象的实例。
Java堆可以处于物理上不连续的内存空间,但对于大对象可能会要求连续的内存空间。Java堆既可以被实现成固定大小,也可以是可扩展的。如果在java堆中没有完成实例分配,并且堆也无法再扩展时,java虚拟机会抛出OutOfMemoryError异常。

方法区(Method Area)

方法取也是各个线程共享的内存空间。它用于存储已被虚拟机加载的类型信息、常量、静态变量等数据。它不需要连续的内存,可以选择固定大小或者可扩展,甚至可以选择不实现垃圾回收。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载。
如果方法取无法满足新的内存分配需求时,将抛出OutOfMamoryError异常。

运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分。在Class文件中的常量池表(Conatant Pool Table),用于存放编译期生成的各种字面量和富豪饮用,这部分类容将在类加载后存放在方法取的运行常量池中。
运行时常量池相对于相对于Class文件常量池的特征:

  • 具备动态性。并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行时也可以吧新的常量放入池中。
  • 除了保存Class文件中描述的符号引用外,还会把符号引用翻译出来的直接引用也储存在运行时的常量池中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值