jvm数据区域划分(堆,栈,方法区)

                                         jvm数据区域划分

jvm其实是java运行时的数据区域。具体划分如下:

说一下各个划分的区域的功能。

执行引擎:执行引擎可以理解为程序执行的入口,比如操作系统有一个个的小图标,我们点击图标之后,就会执行

某个进程,每个程序运行的时候也需要有接口,这时候执行引擎就是程序运行的接口。

本地库接口:我们知道java是一种托管代码的语言,他的实现都是用汇编语言或者C语言来实现。一些类的信息会被

javac编译成class文件,然后调用本地方法库的方法,调用本地方法的时候就需要本地库接口。

本地库方法:包括一些用汇编语言或者c语言写的函数

程序计数器:程序计数器是一块较小的内存空间。他可以记录当前程序执行的位置。他指向了当前执行的字节码

的行号。通过改变程序计数器的值可以实现分支,循环,跳转,异常处理,县城回复等基础的功能。每个线程都有

一个独立的计数器,这个计数器属于"线程私有"的内存区域。如果虚拟机执行的是java方法,那么程序计数器记录的

是正在执行的字节码指令的地址。如果虚拟机执行的是native方法(操作系统本地的方法),那么程序计数器记录为空。

java虚拟机栈:java虚拟机栈是跟线程的生命周期一致的,他是线程私有的。每开启一个线程就会向内存申请一个

虚拟机栈。线程里的每个方法执行时都会有一个栈帧。用于存储局部变量表,操作数栈,动态链接,方法出口等信

息。比如在方法里定义一个变量,会把这个变量压到这个栈帧中,出栈之后用这个变量,然后这个变量一段时间不

用就会被回收。函数的执行过程其实对应着栈帧的入栈和出栈。局部变量表:存放了编译器可知的基本数据类型,

int,double等。还有对象的引用,可以理解为对象变量。局部变量表是在编译期间确定的。运行期间不会改变局部

变量表的大小。操作数栈:执行方法中的算数运算,调用其他函数的参数传递等。动态链接:class文件中存在

大量的符号引用,字节码中调用方法就是通过以常量池中的符号引用为参数调用方法。这些符号引用一部分会在类

加载阶段或者第一次使用时变成直接引用,这种转化为静态解析,另一部分是在运行期间转化为直接引用,这种方式

称为动态链接。方法出口:方法执行后,有两种方式的方法出口:一种是正常结束后,把返回值返回给调用他的函数,

这种出口是正常完成出口,一般出口地址会记录在程序计数器中。另一种是异常结束,会根据异常处理表确定返回地

址。这里说下个人对符号引用的了解。符号引用可以理解为对一个地址的引用,比如一个类的地址,一个方法的地址,

甚至一个字符串对象的地址。下面来分别说说以上三种的应用场景。

我们在new一个对象时,首先判断指令中参数在常量池中是否有该类的符号引用,没有的话会执行类加载。这时候这个

符号引用可以理解为指向这个类的地址。

上面说到class文件中符号引用存在指向方法的符号引用,所以可以理解符号引用也是可以指向方法的。

比如我们在main函数中写道String a = "love",System.out.println(a) // love 这时候在编译期间会把a当作符号引用,love

存放在字面量中,输出a变量的时候,就会指向love字面量。

java本地方法栈:java本地方法栈和虚拟机栈相似,只不过虚拟机栈是为Java方法服务,而本地方法栈是为本地

方法服务。与虚拟机栈一样,当申请的内存超过虚拟机栈的允许最大深度的时候会报出StackOverFlowError栈溢出

当栈动态扩展之后无法扩展到到需要的内存,申请内存失败的时候就会报出OutOfMemoryError内存溢出。

java堆:java堆是虚拟机所管理内存中最大的一块。java堆是被线程所共享的区域。几乎所有对象的实例都在这里

分配内存。java可能会为每个线程申请一个独立的分配缓冲区(TLAB)。这些缓冲区存储的仍然是对象实例,这样的

目的是为了更好地管理内存。如果对象的实例没有在堆中分配出空间,并且堆无法扩展的时候,就会报

OutOfMemoryError内存溢出。

方法区:方法区是被线程所共享的区域,方法区里存放着编译后加载的类信息,常量,静态变量等。方法区

除了可以选择固定大小或者可扩展内存区域,存储位置不需要连续等和堆相同的特性外,方法区还可以选择是否

实现垃圾回收。方法去申请内存失败会报出OutOfMemoryError内存溢出异常。

运行时常量池:常量池是存在方法区中的。当类被编译成class文件之后,class文件除了记录了类的字段,版本号

方法,接口等,还有常量池。存放着编译期生成的符号引用。比如一个类中有个域或者方法中的变量初始化,

String s="abcd";那么abcd就会在编译时期存在常量池中。变量或者域就会指向常量池中的abcd字符串。常量不一定

在编译期产生,在运行时候也能将常量放在常量池中,比如String类的intern()方法。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值