深入了解Java虚拟机——JVM内存分配

相关引用:
字符串编译期与运行期分析及字符串常量池

Java虚拟机-----方法区和运行时常量池

JVM-String常量池与运行时常量池

深入理解Java虚拟机笔记—运行时栈帧结构

##JVM内存分配
Java虚拟机将在Java程序运行过程中将内存分为不同的数据区域,每个区域都有自己的用途以及生命周期,大致划分如下图:
JVM内存分配

1. 程序计数器(线程私有)

  • 占用很小的内存,可以看做当前线程执行的行号指示器,可以根据程序计数器来获取下一条需要执行的字节码指令。

  • 由于java虚拟机的多线程是根据线程轮流切换并分配处理器执行时间的方式来执行的,而每个线程的执行是相互隔离的,所以每个线程都需要一个程序计数器来指示线程执行位置。所以程序计数器为线程私有。

  • 如果正在执行的是一个java方法,那么程序计数器指向的是当前正在执行的字节码指令的地址,如果正在执行的是一个本地方法,那么程序计数器指向空。

  • 程序计数器创建是会分配固定内存,此区域是唯一一个不会抛出OutOfMemoryError的区域。

  • 此区域完全没有GC的必要(随线程而生,随线程而灭)。

2. 方法区(线程公有)

  • 存储已被虚拟机加载的类信息,常量,静态变量,静态方法等数据。

  • 从它存储的数据信息来看,方法区必须是线程共享的。

  • 由于该区域存储的数据被释放的可能性极小,所以GC 极少或完全不会 对该区域进行垃圾回收(根据虚拟机来定),即使回收,其主要目标是常量池或者类型的卸载。

3.运行时常量池

  • 方法区的一部分

  • 线程共享

  • 虚拟机加载Class后把常量池中的数据放入到运行时常量池。

注 : 此处需要了解三个概念

  1. 常量池 : 常量池在数据编译期被确定,存储的是类,接口,方法中的常量,当然也包括字符串常量。可以理解为类的资源仓库。主要存储字面量和符号引用。
  2. 运行时常量池: 虚拟机加载后把常量池中的数据放入到运行时常量池。运行期间新的常量也可以放入运行时常量池。
  3. 字符串常量池: 常量池的一部分,存储的是编译期以及运行期产生的字符串数据。1.7以后被移到了堆中。

字面量与符合引用的解释

字面量 : 文本字符串,声明为final的常量值等。
符号引用: 类和接口的完全限定名,字段的名称和描述符,方法的名称和描述符。
常量池包含的内容

4. 虚拟机栈(线程私有)

  • 生命周期为线程的生成到消亡。

  • 描述的是java方法执行的内存模型:每个方法执行的同时会在在虚拟机栈中创建一个栈帧,栈帧包含的内容有:局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从开始到执行完成的过程,都是一个栈帧从入栈到出栈的过程。

  • 虚拟机栈中规定了两张异常状况:如果栈深度大于JVM允许的深度时会抛出StackOverflowError。如果动态扩容时拿不到足够的内存,则会抛出OutOfMemoryError。

局部变量表 : 存放编译期可知的各种基本数据类型(boolean,byte,char,short,int,float,long,double)以及引用类型,其中64位的double和long会分配两个局部变量空间,其余的只会分配一个。当执行一个方法时,这个方法的栈帧中局部变量表所占的内存空间是确定的,运行期间不会改变。

操作数栈 : 抱歉,这个概念目前不是很了解,如果有大神知道的话求解答。

动态链接 : 在说明什么是动态连接之前先看看方法的大概调用过程,首先在虚拟机运行的时候,运行时常量池会保存大量的符号引用,这些符号引用可以看成是每个方法的间接引用,如果代表栈帧A的方法想调用代表栈帧B的方法,那么这个虚拟机的方法调用指令就会以B方法的符号引用作为参数,但是因为符号引用并不是直接指向代表B方法的内存位置,所以在调用之前还必须要将符号引用转换为直接引用,然后通过直接引用才可以访问到真正的方法,这时候就有一点需要注意,如果符号引用是在类加载阶段或者第一次使用的时候转化为直接应用,那么这种转换成为静态解析,如果是在运行期间转换为直接引用,那么这种转换就成为动态连接。

方法出口 : 当一个方法被执行完后,有两种方式退出这个方法。第一种是正常执行完成后,根据返回类型判断将返回值传递给上层调用者。第二种是出现异常导致方法退出,不会产生任何返回值。
无论哪种情况,都要回到方法被调用的位置,方法退出等于把当前栈帧出栈,因此可能执行的操作有:恢复上层的局部变量表和操作数栈,把返回值(如果有的话)压入到栈帧的操作数栈中,程序计数器的值执行下一条指令。


5. 本地方法栈(线程私有)

  • 和虚拟机栈区别在于虚拟机栈是为java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。

6. 堆(线程公有)

  • 内存最大的一块。

  • GC的重点关注对象

  • 几乎唯一的目的就是存放对象实例和数组

  • 内存分配时,在物理上可以不连续,但逻辑上必须连续。

  • 当堆内存空间不足以创建实例对象时,会抛出OutOfMemoryError。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值