【JavaEE初阶】了解JVM

2023-10-16 15:05:03 浏览数 (1)

一. JVM内存区域划分

JVM启动的时候,会申请到一整个很大的内存区域.JVM是一个应用程序,要从操作系统里申请内存.JVM就根据需要,把空间分为几个部分,每个部分各自有不同的功能.具体划分如下:

  • Native Method Stacks(本地方法栈):native表示是JVM内部的C 代码.就是给调用native方法(JVM内部的方法)准备的栈空间.
  • Program Counter Register(程序计数器):记录当前线程执行到那个命令.(很小的一块存一个地址)每个线程有一份.
  • JVM Stack(虚拟机栈):虚拟机栈是给Java代码使用的栈. 此栈是JVM中一个特定的空间,对于 JVM虚拟机栈 ,这里存储的是方法之间的调用关系.整个栈空间内部,可以认为是包含很多个元素(每个元素表示一个方法),把这里的每个元素称为**“栈帧”,这一个栈帧里,会包含这个方法的入口地址,方法的参数,返回地址,局部变量等. 而对于 本地方法栈 , 存储的是native方法之间的调用关系**. 虚拟机栈,不是只有一个,而是有很多个,每个线程都有一个.

由于函数调用,是有先进后出特点的.此处的栈,也是先进后出的. 栈空间整体一般都不会很大,但是每个栈帧其实占得空间比较小,一般代码无限递归才会出现栈溢出情况.

  • Heap(堆):整个JVM空间最大的区域.new出来的对象,类的成员变量,都在堆上.**堆是一个进程只有一份,栈是每个线程有一份.**一个进程里有多个线程.所以一个进程有多个栈.每个jvm就是一个java进程.

注意这里的常见说法:栈是线程私有的.(此说法不完全对).私有的意思是我的你用不了.实际上,一个线程栈上的内容,可以被另一个线程使用.比如通过变量捕获,一个线程可以访问到另一个线程的局部变量.

  • Metaspace(元数据区):即方法区.一个进程里只有一块,多个线程共用一块.

小结:

  • 局部变量 在 栈
  • 普通成员变量 在 堆
  • 静态成员变量 在 方法区/元数据区

二. JVM类加载机制

2.1 类加载整体流程

类加载,准确的说,类加载就是.class文件,从文件(硬盘)被加载到内存中(元数据区)这样的过程.这个过程是非常复杂的. .class文件可以有多个类对象 .class文件是编译后的Java源代码,它包含了编译后的字节码指令. 类加载主要分为以下几个过程:

  • 加载:把.class文件找到(找的过程),打开文件,地文件,把文件内容读到内存中.
  • 验证:检查.class文件格式是否正确. .class文件是一个二进制文件,这里的格式是有严格说明的,官方提供了JVM虚拟机规范.规范文档上描述了.class的格式:

java代码中写的类的所有信息,都会包含在上述.class文件中.使用二进制的方式重新组织.

  • 准备:给类对象分配内存空间(此时内存初始化为全0)
  • 解析:针对字符串常量进行初始化,把符号引用转为直接引用. 字符串常量,得有一块内存空间,存这个字符的实际内容,还得有一个引用,用来保存这个内存空间的起始地址. 在类加载之前,字符串常量,此时是处在.class文件中的,此时这个"引用"记录的并非是字符串常量的真正地址,而是它在文件中的"偏移量".(或者是占位符)(符号引用) 类加载之后,才真正在把这个字符串常量放到内存中,此时才有"内存地址",这个引用才能被真正赋予成指定内存地址.(直接引用) 举个

    0 人点赞