3

JVM内存分配小总结

 2 years ago
source link: https://wendaoit.github.io/2021/09/18/JVM%E5%88%86%E5%9D%97%E5%B0%8F%E6%80%BB%E7%BB%93/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

JVM内存分配小总结

发表于

2021-09-18 更新于 2021-09-26 分类于 JVM

阅读次数: 4 本文字数: 3.3k

JVM中各个变量存放的位置

需要储备的知识点

Java 中的变量根据不同的标准可以分为两类,以其引用的数据类型的不同来划分可分为 “原始数据类型变量和引用数据类型变量”,以其作用范围的不同来区分可分为 “局部变量,实例变量和静态变量”。

实例方法和普通方法

程序| 进程 | 线程

  • JVM 是一份本地化的程序,本质上是可执行的文件,是静态的概念。程序运行起来成为进程,是动态的概念。
  • JAVA进程( java 程序):一个 JVM 实例其实就是 JVM 跑起来的进程。
  • 各个 JVM 实例之间是相互隔离的。eg:登录了多个QQ
  • 进程:是并发执行的程序在执行过程中分配和管理资源的基本单位。
  • 线程:线程有时又被称为轻权进程或轻量级进程,也是 CPU 调度的一个基本单位。线程之间共用一个进程的内存空存空间 (即 jvm 堆内存),各个线程也有自己独立专有的内存空间 (即 jvm 栈帧空间)。看下图就明白了

首先确定一下jkd1.8之后的JVM内存模型

JVM内存模型

JVM内存模型

image-20210918141601102.png

方法变量内存分配图

img

class Fruit {
static int x = 10;
static BigWaterMelon bigWaterMelon_1 = new BigWaterMelon(x);
int y = 20;
BigWaterMelon bigWaterMelon_2 = new BigWaterMelon(y);

public static void main(String[] args) {
final Fruit fruit = new Fruit();

int z = 30;
BigWaterMelon bigWaterMelon_3 = new BigWaterMelon(z);

new Thread() {
@Override
public void run() {
int k = 100;
setWeight(k);
}

void setWeight(int waterMelonWeight) {
fruit.bigWaterMelon_2.weight = waterMelonWeight;
}
}.start();
}
}

class BigWaterMelon {
public BigWaterMelon(int weight) {
this.weight = weight;
}

public int weight;
}

结合上图可得:

  • 每个 Java 方法在被调用的时候都会创建一个栈帧,并入栈。一旦完成调用,则出栈。所有的的栈帧都出栈后,线程也就完成了使命。

本地方法栈

  • 本地方法栈为虚拟机使用到的 native 方法服务

JAVA Stack

​ 栈中有栈帧,栈帧内存:

  • 8 中基本类型变量 (byte(8)、short(16)、int(32)、long(64)、float(12)、double(64)、char(16)、boolean;)
  • 对象的引用变量(Fruit fruit ) 、
  • 实例方法(方法出口)、
  • 局部变量表;
  • 操作数栈(程序计数器)、
Java.lang.StackOverflowError 栈内存溢出

一个JVM只存在一个堆内存,堆内存的大小是可以调节的。

  • 储存:运行时常量池(字符串拼接得到的P141)、实例变量eg:new Fruit、(也叫成员变量)、静态变量
  • 两个区域:新生代(8:1:1)、老年代()
  • ​ Java 虚拟机可以支持多个线程同时执行,每个线程都有自己的程序计数器。在任何时刻,每个线程都只会执行一个方法的代码,这个方法称为该线程的当前方法(current method)。

    如果线程正在执行的是 Java 方法(不是 native 的),则程序计数器记录的是正在执行的 Java 虚拟机字节码指令的地址。如果正在执行的是本地(native)方法,那么计数器的值是空的(undefined)。

元空间(以前的永久代/方法区)

  • Caused by: java.lang.OutOfMemoryError: Metaspace

  • 储存信息

    • 类加载器读取了类文件后,需要把Class metadata(类元数据)、方法模板(构造方法)、常变量放到元空间中;

Java 中有哪几种常量池?

class 文件常量池、运行时常量池、字符串常量池。

class 文件常量池

class 文件常量池(class constant pool)属于 class 文件的其中一项,class 类文件包含:类的版本、常量池、访问标志、字段表集合、方法表等信息。

常量池用于存放编译期间生成的各种字面量(Literal)和符号引用(Symbolic References)。

运行时常量池

class 文件常量池是在类被编译成 class 文件时生成的。而当类被加载到内存中后,JVM 就会将 class 文件常量池中的内容存放到运行时常量池中。

Java 虚拟机规范中对运行时常量池的定义如下:

A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file.

运行时常量池是 class 文件中每一个类或接口的常量池表(constant_pool table)的运行时表示形式。

因此,根据规范定义,可以说运行时常量池是 class 文件常量池的运行时表示,每个类在运行时都有自己的一个独立的运行时常量池。

字符串常量池

简单来说,HotSpot VM 里的字符串常量池(StringTable)是个哈希表,全局只有一份,被所有的类共享。

StringTable 具体存储的是 String 对象的引用,而不是 String 对象实例自身。String 对象实例在 JDK 6 及之前是在永久代里,从 JDK 7 开始放在堆里。

根据 Java 虚拟机规范的定义,堆是存储 Java 对象的地方,其他地方是不会有 Java 对象实体的,如果有的话,根据规范定义,这些地方也要算堆的一部分。

jdk1.8之后永久代的变化

永久代在 Java 8 被移除。根据官方提案的描述,移除的主要动机是:要将 JRockit 和 Hotspot 进行融合,而 JRockit 并没有永久代。

而据我们所了解的,还有另外一个重要原因是永久代本身也存在较多的问题,经常出现 OOM,还出过不少 bug。

根据官方提案的描述,永久代主要存储了三种数据:

1)Class metadata(类元数据),也就是方法区中包含的数据,除了编译生成的字节码被放在 native memory(本地内存)。

2)interned Strings,也就是字符串常量池中驻留引用的字符串对象,字符串常量池只驻留引用,而实际对象是在永久代中。

3)class static variables,类静态变量。

移除永久代后,interned Strings 和 class static variables 被移动了堆中,Class metadata 被移动到了后来的元空间。

为什么引入元空间?

在 Java 8 之前,Java 虚拟机使用永久代来存放类元信息,通过 - XX:PermSize、-XX:MaxPermSize 来控制这块内存的大小,随着动态类加载的情况越来越多,这块内存变得不太可控,到底设置多大合适是每个开发者要考虑的问题。

如果设置小了,容易出现内存溢出;如果设置大了,又有点浪费,尽管不会实质分配这么大的物理内存。

而元空间可以较好的解决内存设置多大的问题:当我们没有指定 -XX:MaxMetaspaceSize 时,元空间可以动态的调整使用的内存大小,以容纳不断增加的类。

元空间(metaspace)

元空间在 Java 8 移除永久代后被引入,用来代替永久代,本质和永久代类似,都是对方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存(native memory)。

元空间主要用于存储 Class metadata(类元数据),根据其命名其实也看得出来。

可以通过 -XX:MaxMetaspaceSize 参数来限制元空间的大小,如果没有设置该参数,则元空间默认限制为机器内存。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK