JDK13版系列文章-2

	在c,c++中,程序员拥有每个对象的所有权,但是也肩负着释放内存空间的责任,Java虽然没有拥有所有权,但是也去掉了,内存释放的职责。java内存这块的处理,由jvm自动进行内存的释放。

首先呢,还是先回避一下,一些瞎扯的谬论,
谬论1:官方在jdk1.8移除了方法区,替换为元空间了

我们直接上官方jvm文档的图
在这里插入图片描述
官方还是规范中方法区的,那么被移除的是谁呢?永久代。
这东西后面会详细说到,先介入正题
jvm内存的一个划分

在这里插入图片描述
开始慢慢解析这个内存划分
运行时数据区:
Java虚拟机定义了在程序执行期间使用的各种运行时数据区域。其中一些数据区域是在Java虚拟机启动时创建的,仅在Java虚拟机退出时才被销毁。其他数据区域是每个线程的。在创建线程时创建每个线程的数据区域,并在线程退出时销毁每个数据区域。
pc寄存器(程序计数器):
Java虚拟机可以一次支持多个执行线程。每个Java虚拟机线程都有其自己的 pc(程序计数器)寄存器。在任何时候,每个 Java 虚拟机线程只会执行一个方法的代码,这个正在被线程执行的方法称为该线程的当前方法。。如果不是 native,则该pc寄存器包含当前正在执行的Java虚拟机指令的地址。如果线程当前正在执行的方法是native,则Java虚拟机的pc 寄存器值未定义。
其实就是一小块内存,记录着当前程序运行到哪了字节码解释器的工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。分支,循环,跳转,异常处理,线程回复等都需要依赖这个完成。
程序计数器特点:
线程隔离性,每个线程工作时都有属于自己的独立计数器。
执行java方法时,程序计数器是有值的,且记录的是正在执行的字节码指令的地址。
执行native本地方法时,程序计数器的值为空(Undefined)。因为native方法是java通过JNI直接调用本地C/C++库,可以近似的认为native方法相当于C/C++暴露给java的一个接口,java通过调用这个接口从而调用到C/C++方法。由于该方法是通过C/C++而不是java进行实现。那么自然无法产生相应的字节码,并且C/C++执行时的内存分配是由自己语言决定的,而不是由JVM决定的。
程序计数器占用内存很小,在进行JVM内存计算时,可以忽略不计。
程序计数器,是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError的区域。

Java虚拟机栈:

每一条 Java 虚拟机线程都有自己私有的 Java 虚拟机栈,这个栈与线程同时创建,用于存储栈帧。如果线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量时, Java 虚拟机将会抛出一个 StackOverflowError 异常。
从上面的例子,看到了一个词,栈帧,这东西又是什么呢

栈帧:

用来存储方法数据和部分过程结果的数据结构,每调用一个方法时就会往栈中创建并压入一个栈帧。
栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。
每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机里面从入栈到出栈的过程。
在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧,与这个栈帧相关联的方法称为当前方法。执行引擎运行的所有字节码指令都只针对当前栈帧进行操作。

局部变量表:

一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。
栈帧中局部变量表的长度由编译期决定,并且存储于类和接口的二进制表示之中,既通过方法的Code 属性保存及提供给栈帧使用。在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。
局部变量表存放了编译期可知的各种基本数据类型、reference类型(对象引用) 和 returnAddress类型。使用索引来进行定位访问,第一个局部变量的索引值为零,局部变量的索引值是从零至小于局部变量表最大容量的所有整数。局部变量第一个局部变量,一定是当前对象的引用,即this关键字。
局部变量存储在局部变量表中,随着线程而生,线程而灭。并且线程间数据不共享。
局部变量表的容量以变量槽为最小单位,每个变量槽都可以存储32位长度的内存空间,例如boolean、byte、char、short、int、float、reference(引用)。
对于64位长度的数据类型(long,double),虚拟机会以高位对齐方式为其分配两个连续的槽空间,也就是相当于把一次long和double数据类型读写分割成为两次32位读写。(为了尽可能节省栈帧空间,局部变量表中的槽是可以重用的,也就是说当PC计数器的指令指已经超出了某个变量的作用域(执行完毕),那这个变量对应的槽就可以交给其他变量使用。)
对象实例的引用(reference):它的本质是一个地址(类似一个网页链接),并不是对象本身,不同的虚拟机这个地址指向的内容也不一样;这个指针可能指向一个对象的起始地址,也可能指向一个代表对象的句柄。
returnAddress类型本质上是一个地址,这个地址指向一条字节码执行。

动态链接:讲这个之前,先谈谈,静态链接

静态链接:在Class文件中的常量池中存有大量的符号引用(一个方法调用另一个方法,或者一个类使用另一个类的成员变量时,需要知道其名字符号引用就相当于名字,这些被调用者的名字就存放在Java字节码文件里)。字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分在类的加载阶段或第一次使用的时候就转化为了直接引用(指向数据所存地址的指针、句柄等),这个转换就是静态链接。
动态链接:另一部分在运行期间转化为直接引用,就称为动态链接。
方法出口:方法返回地址,当一个方法开始执行后,只有2种方式可以退出这个方法

方法返回指令 :

执行引擎遇到一个方法返回的字节码指令,这时候有可能会有返回值传递给上层的方法调用者,这种退出方式称为正常完成出口。方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中会保存这个计数器值。
  异常退出 : 在方法执行过程中遇到了异常,并且没有处理这个异常,就会导致方法退出。方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息。
  无论采用任何退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息。
本地方法栈、JNI和堆,明天继续。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值