jvm运行时数据区详解

目录

一、引言

二、java程序的执行过程

三、运行时数据区域 

1.程序计数器

2.虚拟机栈

2.1栈区的存储结构和运行原理

2.2局部变量表

2.3操作数栈

2.4动态链接

2.5方法返回地址

3.本地方法栈

3.堆区

4.方法区

四、总结


一、引言

对于C、C++程序开发人员来讲,他们既是“皇帝”又是从事基础工作的“劳动人民”--既有每个对象的所有权,又担负每个对象的生命周期。对于Java程序员,在虚拟机自动内存管理机制帮助下,不用写malloc和free配对的代码,不容易出现内存泄露和内存溢出的问题,但是一旦出现问题,如果不了解虚拟机是怎样使用内存的,那么排查起来将异常艰难。

二、java程序的执行过程

一个 Java 程序,首先经过 javac 编译成 .class 文件,然后 JVM 将其加载到方法区,执行 引擎将会执行这些字节码。执行时,会翻译成操作系统相关的函数。JVM 作为 .class 文件的翻译 存在,输入字节码,调用操作系统函数。

过程如下:Java 文件->编译器>字节码->JVM->机器码。

JVM 全称 Java Virtual Machine,也就是我们耳熟能详的 Java 虚拟机。它能识别 .class后缀 的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作

三、运行时数据区域 

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域

Java 引以为豪的就是它的自动内存管理机制。相比于 C++的手动内存管理、复杂难以理解java的内存管理方便实用

所以要深入理解JVM必须理解内存虚拟化的概念。

在JVM中,JVM 内存主要分为堆、程序计数器、方法区、虚拟机栈和本地方法栈等。

1.程序计数器

较小的内存空间,当前线程执行的字节码的行号指示器;各线程之间独立存储,互不影响。

程序计数器是一块很小的内存空间,主要用来记录各个线程执行的字节码的地址,例如,分支、循环、跳转、异常、线程恢复等都依赖于计数器。

由于 Java 是多线程语言,当执行的线程数量超过 CPU 核数时,线程之间会根据时间片轮询争夺 CPU 资源。如果一个线程的时间片用完了,或者是其它原因导致这个线程的 CPU 资源被提前抢夺,那么这个退出的线程就需要单独的一个程序计数器,来记录下一条运行的指令。

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址

2.虚拟机栈

每个线程私有的,线程在运行时,在执行每个方法的时候都会打包成一个栈帧,存储了局部变量表,操作数栈,动态链接,方法出口等信息,然后放入栈。每个时刻正在执行的当前方法就是虚拟机栈顶的栈桢。方法的执行就对应着栈帧在虚拟机栈中入栈和出栈的过程。

栈的大小缺省为1M。

2.1栈区的存储结构和运行原理

2.2局部变量表

是一个数组类型,存放编译期可知的各种基本数据类型(byte,boolean,char,short,int,float,long,double)、对象引用。64位的long和double类型占两个局部变量空间,其余类型占用一个。

2.3操作数栈

每一个独立的栈帧中除了包含局部变量表之外还包含一个后进先出的操作数栈。

作用:在方法执行过程中根据字节码指令,往栈中写入数据或者提取数据 某些字节码指令将值压入操作数栈,其余的字节码指令将操作数取出栈,使用他们后再把结果压入 其中
比如:复制、交换、求和、求余等操作

2.4动态链接

每一个栈帧内部都包含一个执行运行时常量池中该栈帧所述方法的引用。包含这个引用的目的是为 了支持当前方法的代码能够实现动态链接(invokeDynamic指令)

在Java源文件被编译到字节码文件中是,所有的变量和方法引用都作为符号引用保存在class文件的 常量池里。

例:描述一个方法调用另外一个方法是,就是通过常量池中的执行方法符号引用来标识,那么动态 链接的作用就是为了将这些符号引用转换为调用方法的直接引用

2.5方法返回地址

存放调用方法的PC寄存器的值

一个方法的结束,有两种方式:

正常执行完成

出现未处理的异常退出

无论通过那种方式退出,在方法退出后返回到该方法被调用的位置。方法正常退出是,调用者的PC 寄存器的值作为返回地址,即调用该方法的指令的吓一条指令的地址。

3.本地方法栈

本地方法栈跟 Java 虚拟机栈的功能类似,Java 虚拟机栈用于管理 Java 函数的调用,而本地方法栈则用于管理native方法的调用。但本地方法并不是用 Java 实现的,而是由 C 语言实现的(比如Object.hashcode方法)。

本地方法栈是和虚拟机栈非常相似的一个区域,它服务的对象是 native 方法。你甚至可以认为虚拟机栈和本地方法栈是同一个区域。

虚拟机规范无强制规定,各版本虚拟机自由实现 ,HotSpot直接把本地方法栈和虚拟机栈合二为一 。

3.堆区

是java虚拟机管理内存中最大的一块,被所有线程共享,在虚拟机启动时创建,此内存区域的目的是存放对象实例,几乎所有对象都在这里分配,Java堆也是垃圾收集的主要区域。

4.方法区

方法区(Method Area)是可供各条线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池(Runtime Constant Pool)字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法。JDK1.7之前也称为永久代,JDK1.8及以后使用元空间实现

运行时常量池:用于存放编译期生成的各种字面量和符号引用,字面量可以理解为实际的值,比如int a=8中的8和String a="hello"中的hello属于字面量,符号引用就是字符串,可以时常量和变量,比如a就是符号引用,类加载时会将符号引用替换成直接引用(指针)。 

四、总结

1.JVM 向操作系统申请内存:

JVM 第一步就是通过配置参数或者默认配置参数向操作系统申请内存空间,根据内存大小找到具体的内存分配表,然后把内存段的起始地址和终止地址分配给 JVM,JVM 获得内存空间后,会根据配置参数分配堆、栈以及方法区的内存大小

-Xms30m -Xmx30m  -Xss1m -XX:MaxMetaspaceSize=30m

2.类加载:

这里主要是把class放入方法区、还有class中的静态变量和常量也要放入方法区

3.执行方法及创建对象:

启动 main 线程,执行 main 方法,开始执行第一行代码。此时堆内存中会创建一个 student 对象,对象引用 student 就存放在栈中。

后续代码中遇到new关键字,会再创建一个 student 对象,对象引用 student 就存放在栈中。

参考:

《深入理解Java虚拟机》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值