JVM内存管理

以下内容:并非作者自己总结,勿喷


JVM.png

android大概了解这些
总结:JVM运行时数据区主要有 私有区域 java栈(先进后去,里面有N个栈帧) 本地栈(native栈), 程序计数器
共享区域 方法区: 存放 类信息 常量 静态变量 即时编译期编译后的代码
堆:new出来的对象

一:JVM是什么?

可以理解成只是一个翻译;
它可以跨平台,跨语音; 各种语言编译成字节码,然后通过JVM运行到各种平台上;

二:JVM的跨平台与语言无关性

JVM的跨平台
JVM的语言无关性

跨平台性.png

三:JVM的整体

JVM的整体.png

JVM的运行过程

java文件 --》javac翻译,生成class文件,通过类加载器classLoader,JVM会把class加载到运行时数据区(内存),在通过执行引擎
到操作系统上;

JVM就是把字节码翻译成机器码

四:什么是运行时数据区?

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域

它有如下类型

程序计数器、虚拟机栈、本地方法栈、Java堆、方法区(运行时常量池)、直接内存


运行时数据区域.jpg
  • 1,白色部分就是线程私有的;
  • 2,灰色部分不受线程控制的,共享区域;

线程私有区域

4.1 程序计数器

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

记录某个线程当前程序运行到那个位置;如图

4.1 .1:为什么需要这个程序计数器?

答:JVM是个软件,有可能程序在跑的时候,cpu被切换出去了(时间轮转机制),无论单线程还是多线程,有可能程序被终止,这个时候需要记录程序运行到哪一行;

4.1 .2:JVM内存区域中 唯一不会OOM ;

答: 因为它要记录一个地址;

运行内存区域.png

4.2 虚拟机栈(JAVA栈)

  • 比较重要的一片区域;存储当前线程运行方法所需的数据,指令、返回地址;
  • 它具有先进后出的特点
  • 有大小限制

4.2.1:什么是栈帧?

  • 虚拟机栈比喻成子弹夹,那栈帧就是子弹;一个方法对应一个栈帧;如图上面的 运行内存区域.png
  • 它包括:局部变量表, 操作数栈 , 动态连接, 完成出口

java 解释执行是栈(操作数栈)兼容性好,效率偏低,c是寄存器(硬件运算)。移植性差

4.3 本地方法栈(native区)

本地方法栈保存的是native方法的信息,
本地方法栈跟 Java 虚拟机栈的功能类似,Java 虚拟机栈用于管理 Java 函数的调用,而本地方法栈则用于管理本地方法的调用。但本地方法并不是用 Java 实现的,而是由 C 语言实现的。

当一个JVM创建的线程调用native方法后,JVM不再为其在虚拟机栈中创建栈帧,JVM只是简单地动态链接并直接调用native方法

虚拟机规范无强制规定,各版本虚拟机自由实现 HotSpot直接把本地方法栈和虚拟机栈合二为一

线程共享的区域

4.4方法区

存放以下数据

  • 类信息
  • 常量
  • 静态变量
  • 即时编译期编译后的代码

4.4 堆(java堆)

  • 对象实例(几乎所有)
  • 数组

Java堆的大小参数设置

-Xmx 堆区内存可被分配的最大上限
-Xms 堆区内存初始内存分配的大小

4.4:为什么共享区域不共用一个区域要分方法区和堆?

堆:对象和数组,频繁的回收;

直接内存

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

五:从底层深入理解运行时数据区

image.png

上面代码内存分布图如下:


image.png

六:深入辨析堆和栈

功能角度:

  • 以栈帧的方式存储方法调用的过程,并存储方法调用过程中基本数据类型的变量(int、short、long、byte、float、double、boolean、char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放;
  • 而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中;

线程独享还是共享:

  • 栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
  • 堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

空间大小

栈的内存要远远小于堆内存

六:内存溢出

  • 栈溢出
    StackOverflowError 递归容易出现

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

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

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

七:虚拟机优化技术

编译优化技术——方法内联

image.png

方法内联的优化行为,就是把目标方法的代码原封不动的“复制”到调用的方法中,避免真实的方法调用而已。

栈的优化技术——栈帧之间数据的共享

在一般的模型中,两个不同的栈帧的内存区域是独立的,但是大部分的JVM在实现中会进行一些优化,使得两个栈帧出现一部分重叠。(主要体现在方法中有参数传递的情况),让下面栈帧的操作数栈和上面栈帧的部分局部变量重叠在一起,这样做不但节约了一部分空间,更加重要的是在进行方法调用时就可以直接公用一部分数据,无需进行额外的参数复制传递了。


image.png

你可能感兴趣的:(JVM内存管理)