JVM虚拟机—内存管理

JVM虚拟机—内存管理

JVM内存布局

java的数据结构是非常丰富的,例如:

  • 静态成员变量
  • 动态成员变量
  • 区域变量
  • 短小紧凑的对象声明
  • 庞大复杂的内存申请

这么多不同的数据结构,是在什么地方存储的,它们之间又是如何交互的呢?

​ java的内存布局是一直在调整的。JDK8之后的版本移除了永久代,使用metadata来代替。这表示-XX:PermSIze等参数调优已经没有了意义。

JVM虚拟机—内存管理_第1张图片

JVM内存区域划分如图。

  • JVM堆中的数据是共享的,是占用内存最大的一块区域。
  • 可以执行字节码的模块叫做执行引擎
  • 程序计数器用来堆执行引擎的线程进行切换
  • 栈、本地方法栈与多线程相关
  • 本地内存包含元空间和直接内存、
虚拟机栈

​ Java的虚拟机栈是基于线程的。main方法也是以线程的方式运行的,参与计算的数据会出栈、入栈。栈的生命周期和线程一样。栈里的每条数据,叫做栈帧。在每个方法被调用时,都会创建一个栈帧,并入栈。完成相应的调用就出栈。所有的栈帧出栈后,线程结束。

​ 每个栈帧都包含四个区域。

  • 局部变量表
  • 操作数栈
  • 动态连接
  • 返回地址

​ 本地方法栈和虚拟机栈非常相似,它服务的对象是native方法(非Java方法)。

JVM虚拟机—内存管理_第2张图片

​ 程序就是存储在方法区的字节码指令。返回地址returnAdress就是指向这些特定程序内存地址的指针。

这里有两层栈。第一层栈帧对应方法。第二层是方法的执行,对应着操作数。

程序计数器

​ 设想一下,如果我们的程序在线程之间切换,凭什么能够知道这个线程已经执行到什么地方呢。

​ 程序计数器是一块比较小的空间,它的作用可以理解为当前线程所执行字节码的行数显示器。程序计数器由线程产生的。它存储了当前正在运行的流程,包括正在执行的指令、跳转、分支、循环、异常处理等。

​ 堆是JVM中的最大内存区域,我们申请的几乎所有的对象都在这里存储。我们的垃圾回收器,回收的就是堆内存。随着对象的频繁创建,堆空间越来越大,就需要不定时对不再使用的对象进行回收,这个过程叫做GC。

​ 在长时间的运行之后,堆空间会被很多细小的碎片占满,造成空间浪费,所以还需要进行堆空间整理。

​ 那一个对象创建的时候,是在堆中呢还是栈中?这个和对象的类型、在Java类中的位置有关。java的对象可以分为基本数据类型和普通对象。

​ 对于普通对象,JVM会在堆上创建对象,然后在其他地方使用它的引用,比如将这个引用保存在局部变量表中。

而基本数据类型会分配在栈中

元空间

关于元空间有这样一个面试题:“为什么有 Metaspace 区域?它有什么问题?”

​ 在Java 8之前,类的信息是放在Perm区的内存中的。更早版本,运行时常量池也放在这里。这个区域大小有限,很容易造成内存溢出。原来的Perm是在堆上的,现在的元空间是在非堆上的。

​ 元空间虽然可以使用操作系统内存,但是无限制的使用会使操作系统崩溃。所以可以使用-XX:MaxMetaspaceSize 来限制。

​ 方法区是一个概念,它的物理存储就是元空间。元空间中包含类的信息、运行时常量池、方法数据、方法代码。

字符串常量池在JDK7之后移到了堆中

你可能感兴趣的:(JVM虚拟机)