美文网首页
JVM 内存管理

JVM 内存管理

作者: 我要离开浪浪山 | 来源:发表于2021-09-01 00:09 被阅读0次

1、Java Virtual Machine

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

Java 程序不一样,使用 javac 编译成 .class 文件之后,还需要使用 Java 命令去主动执行它,操作系统并不认识这些 .class 文件。所以JVM就是一个翻译。

图片.png

2、Java从编译到运行

图片.png

3、JVM的跨平台与语言无关性

图片.png

4、运行时数据区域

图片.png

5、JAVA方法运行的内存区域

图片.png

6、程序计数器

指向当前线程正在执行的字节码指令的地址

  • 较小的内存空间,当前线程执行的字节码的行号指示器;各线程之间独立存储,互不影响。
  • 程序计数器是一块很小的内存空间,主要用来记录各个线程执行的字节码的地址,例如,分支、循环、跳转、异常、线程恢复等都依赖于计数器。
  • 由于 Java 是多线程语言,当执行的线程数量超过 CPU 核数时,线程之间会根据时间片轮询争夺 CPU 资源。如果一个线程的时间片用完了,或者是其它原因导致这个线程的 CPU 资源被提前抢夺,那么这个退出的线程就需要单独的一个程序计数器,来记录下一条运行的指令。
    程序计数器也是JVM中唯一不会OOM(OutOfMemory)的内存区域

7、虚拟机栈

  • 栈是什么样的数据结构?先进后出(FILO)的数据结构,

  • 虚拟机栈在JVM运行过程中存储当前线程运行方法所需的数据,指令、返回地址。

  • Java 虚拟机栈是基于线程的。哪怕你只有一个 main() 方法,也是以线程的方式运行的。在线程的生命周期中,参与计算的数据会频繁地入栈和出栈,栈的生命周期是和线程一样的。

  • 栈里的每条数据,就是栈帧。在每个 Java 方法被调用的时候,都会创建一个栈帧,并入栈。一旦完成相应的调用,则出栈。所有的栈帧都出栈后,线程也就结束了。

  • 每个栈帧,都包含四个区域:(局部变量表、操作数栈、动态连接、返回地址)

  • 栈的大小缺省为1M,可用参数 –Xss调整大小,例如-Xss256k

  • 局部变量表:顾名思义就是局部变量的表,用于存放我们的局部变量的。首先它是一个32位的长度,主要存放我们的Java的八大基础数据类型,一般32位就可以存放下,如果是64位的就使用高低位占用两个也可以存放下,如果是局部的一些对象,比如我们的Object对象,我们只需要存放它的一个引用地址即可。

  • 操作数据栈:存放我们方法执行的操作数的,它就是一个栈,先进后出的栈结构,操作数栈,就是用来操作的,操作的的元素可以是任意的java数据类型,所以我们知道一个方法刚刚开始的时候,这个方法的操作数栈就是空的,操作数栈运行方法就是JVM一直运行入栈/出栈的操作
  • 动态连接:Java语言特性多态(需要类运行时才能确定具体的方法)。
  • 返回地址:正常返回(调用程序计数器中的地址作为返回)、异常的话(通过异常处理器表<非栈帧中的>来确定)


    图片.png

8、本地方法栈

  • 本地方法栈跟 Java 虚拟机栈的功能类似,Java 虚拟机栈用于管理 Java 函数的调用,而本地方法栈则用于管理本地方法的调用。但本地方法并不是用 Java 实现的,而是由 C 语言实现的。
图片.png

9、线程共享的区域

图片.png

10、方法区/永久代

  • 很多开发者都习惯将方法区称为“永久代”,其实这两者并不是等价的。
  • 方法区主要是用来存放已被虚拟机加载的类相关信息,包括类信息、静态变量、常量、运行时常量池、字符串常量池。
  • 方法区与堆空间类似,也是一个共享内存区,所以方法区是线程共享的。假如两个线程都试图访问方法区中的同一个类信息,而这个类还没有装入 JVM,那么此时就只允许一个线程去加载它,另一个线程必须等待。在 HotSpot 虚拟机、Java7 版本中已经将永久代的静态变量和运行时常量池转移到了堆中,其余部分则存储在 JVM 的非堆内存中,而 Java8 版本已经将方法区中实现的永久代去掉了,并用元空间(class metadata)代替了之前的永久代,并且元空间的存储位置是本地

元空间大小参数:

  • jdk1.7及以前(初始和最大值):-XX:PermSize;-XX:MaxPermSize;
  • jdk1.8以后(初始和最大值):-XX:MetaspaceSize; -XX:MaxMetaspaceSize
  • jdk1.8以后大小就只受本机总内存的限制(如果不设置参数的话)

11、堆

  • 堆是 JVM 上最大的内存区域,我们申请的几乎所有的对象,都是在这里存储的。我们常说的垃圾回收,操作的对象就是堆。
  • 堆空间一般是程序启动时,就申请了,但是并不一定会全部使用。
  • 随着对象的频繁创建,堆空间占用的越来越多,就需要不定期的对不再使用的对象进行回收。这个在 Java 中,就叫作 GC(Garbage Collection)。
  • 那一个对象创建的时候,到底是在堆上分配,还是在栈上分配呢?这和两个方面有关:对象的类型和在 Java 类中存在的位置。
  • Java 的对象可以分为基本数据类型和普通对象。
  • 对于普通对象来说,JVM 会首先在堆上创建对象,然后在其他地方使用的其实是它的引用。比如,把这个引用保存在虚拟机栈的局部变量表中。
  • 对于基本数据类型来说(byte、short、int、long、float、double、char),有两种情况。当你在方法体内声明了基本数据类型的对象,它就会在栈上直接分配。其他情况,都是在堆上分配。

堆大小参数:
-Xms:堆的最小值;
-Xmx:堆的最大值;
-Xmn:新生代的大小;
-XX:NewSize;新生代最小值;
-XX:MaxNewSize:新生代最大值;
例如- Xmx256m

12、直接内存

  • 不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域;如果使用了NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作;
  • 这块内存不受java堆大小限制,但受本机总内存的限制,可以通过-XX:MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常。

13、深入辨析堆和栈

功能

  • 以栈帧的方式存储方法调用的过程,并存储方法调用过程中基本数据类型的变量(int、short、long、byte、float、double、boolean、char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放;
  • 而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中;
    线程独享还是共享
  • 栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
  • 堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
    空间大小
  • 栈的内存要远远小于堆内存

14、栈溢出

  • OutOfMemoryError:不断建立线程,JVM申请栈内存,机器没有足够的内存。(一般演示不出,演示出来机器也死了)

15、堆溢出

  • 内存溢出:申请内存空间,超出最大堆内存空间。
  • 如果是内存溢出,则通过 调大 -Xms,-Xmx参数。
  • 如果不是内存泄漏,就是说内存中的对象却是都是必须存活的,那么久应该检查JVM的堆参数设置,与机器的内存对比,看是否还有可以调整的空间,再从代码上检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理等情况,尽量减少程序运行时的内存消耗。

16、方法区溢出

(1)运行时常量池溢出
(2)方法区中保存的Class对象没有被及时回收掉或者Class信息占用的内存超过了我们配置。

注意Class要被回收,条件比较苛刻(仅仅是可以,不代表必然,因为还有一些参数可以进行控制):

1、 该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。

2、 加载该类的ClassLoader已经被回收。

3、 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

17、 本机直接内存溢出

  • 直接内存的容量可以通过MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常;
  • 由直接内存导致的内存溢出,一个比较明显的特征是在HeapDump文件中不会看见有什么明显的异常情况,如果发生了OOM,同时Dump文件很小,可以考虑重点排查下直接内存方面的原因。

相关文章

  • 初见JVM内存区域

    初见JVM内存区域 JVM一个重要的机制就是自动内存管理机制,为了深入理解JVM的内存管理机制,了解JVM的内存...

  • 【问答】补充

    Java JVM如何管理内存的? Java中内存管理是JVM自动进行的,创建对象或者变量时JVM会自动分配内存,当...

  • Android性能优化-内存泄漏的几个案例

    JVM内存管理 Java采用GC进行内存管理。深入的JVM内存管理知识,推荐《深入理解Java虚拟机》。 关于内存...

  • [JVM系列]JVM内存管理详解

    JVM内存管理详解

  • Java基础之引用类型

    一、概念 在Java语言中,由JVM进行内存的管理,JVM通过一定的内存回收机制来管理内存,对系统不再使用但JVM...

  • JVM内存结构、运行时内存以及类加载过程

    以下内容都是基于jdk1.8 1、JVM 内存管理 2、JVM内存区域 JVM内存区域主要分为线程私有Thread...

  • JVM内存结构

    以下信息摘录自:深入理解JVM的内存结构及GC机制 JVM内存管理 根据JVM规范,JVM把内存区域划分成了以下几...

  • Java基础

    JVM内存 1、JVM 内存管理和GC知识概述和总结(20190711) https://www.atatech....

  • [JVM] JVM内存结构浅析

    JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策略,保证了JVM高效稳定运行。 经典的JVM内存布...

  • jvm 基础第一节: jvm数据区

    程序内存管理分为手动内存管理和自动内存管理, 而java属于自动内存管理,因此jvm的职能之一就是程序内存管理 j...

网友评论

      本文标题:JVM 内存管理

      本文链接:https://www.haomeiwen.com/subject/ipbtwltx.html