目录
文章内容系个人学习笔记、网课截图和笔记、站内博客资料,如有冒犯,请联系我。
JVM内存结构
Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分为若干个不同的数据区域。每个区域都有各自的作用。
分析 JVM 内存结构,主要就是分析 JVM 运行时数据存储区域。JVM 的运行时数据区主要包括:堆、栈、方法区、程序计数器等。
而 JVM 的优化问题主要在线程共享的数据区中:堆、方法区。
一、程序计数器
Program Counter Register 程序计数器是JVM内存结构的组成部分
一个线程的执行,是通过字节码解释器改变当前线程的程序计数器的值,来获取下一条需要执行的字节码指令,从而确保线程的正确执行
1.1 Java程序执行过程
1、 Java源代码经过编译成为二进制字节码(Jvm指令
2、二进制字节码(Jvm指令)通过 解释器 解释成 机器码
3、将机器码交给 CPU 执行
1.2 程序计数器作用
在指令执行过程中记录下一条Jvm指令的执行地址
1.3 程序计数器特点
1.3.1 线程私有
解释:每一个线程都有属于它自己的程序计数器,即私有的内存
假设有两个线程:线程1 和 线程2
当 线程1 执行到地址为 10 的Jvm指令,
此时程序计数器内存的指令地址为 11 ,
碰巧线程1的CPU时间片用完了,轮到 线程2 执行(上下文切换)
此时 线程1 的程序计数器保持不变,线程2 有它自己的程序计数器
1.3.2 不存在内存溢出OutOfMemoryError
二、虚拟机栈
2.1 定义
栈是线程运行需要的内存空间-是线程私有的,它的生命周期与线程相同。每个线程都会分配一个栈的空间,即每个线程拥有独立的栈空间
2.2 特点
限定仅在表头进行插入和删除操作的线性表。即压栈(入栈)和弹栈(出栈)都是对栈顶元素进行操作的,即先进后出的。
2.3 虚拟机栈内存什么
栈帧是栈的元素
① 栈帧是栈中的一个栈元素,是用于帮助虚拟机执行方法调用与方法执行的数据结构,当前线程中,每执行一个方法就会往栈中插入一个栈帧。
② 栈帧本身是一种数据结构,是每个方法运行时需要的内存,封装了方法的局部变量表、动态链接信息、方法返回地址(即返回到方法的调用者)以及操作数栈
③ Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,换句话说,每个线程都会有一个栈,所以对于栈帧来说不存在并发调用的情况,即线程安全④ 活动栈帧-栈顶的栈帧,即当前执行的栈帧
2.4 栈内存溢出
2.4.1 栈帧过多内存溢出
例如方法的设定不合理,导致无限的递归调用
StackOverflowError:栈溢出错误
如果一个线程在计算时所需要用到栈大小 > 配置允许最大的栈大小,那么Java虚拟机将抛出 StackOverflowError
OutOfMemoryError:内存不足
栈进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。
2.4.2 栈帧过大内存溢出
如栈帧的内存大小超出栈的大小(不易出现)
2.5 线程诊断
案例一:cpu占用过高Linux
- 运行一个java程序
- 使用top命令,查看后台进程对cpu的占用情况
- 查询进程的线程指定指标 ps H -eo pid,tid,%cpu | grep 进程ID
- 查看java进程下的线程运行情况 jstack 进程ID
- 根据ps H -eo pid,tid,%cpu | grep 进程ID 查到的线程ID(10进制)找到对应线程ID(16进制)的信息
三、本地方法栈
3.1 与虚拟机栈对比
① 本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用类似
② 虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈是为虚拟机使用到的本地方法(Native Method)服务
③ 本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常
④ 虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它
当一个线程在运行时会调用JAVA方法和Native方法时,如下图所示(可以相互自由调用)
3.2 Native Method
3.2.1 什么是Native Method
一个Native Method就是一个Java调用非java代码的接口。
Native Method:该方法的实现由非java语言实现,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调用一个C的函数。
3.2.2 为什么调用Native Method
① 与java环境外交互:
有时java应用须要与java外面的环境交互。这是本地方法存在的主要缘由,你能够想一想java须要与一些底层系统如操做系统或某些硬件交换信息时的状况。本地方法正是这样一种交流机制:它为咱们提供了一个很是简洁的接口,并且咱们无需去了解java应用以外的繁琐的细节。