JVM内存结构

本文详细探讨了JVM内存结构,包括程序计数器、虚拟机栈、本地方法栈、堆和方法区(元空间)等各部分的定义、特点、作用以及内存溢出等问题。其中,程序计数器和虚拟机栈是线程私有,本地方法栈服务于本地方法,堆用于存储对象,方法区(元空间)存储类信息、常量等。文章还分析了分代的概念和垃圾回收机制。
摘要由CSDN通过智能技术生成

目录

JVM内存结构

一、程序计数器

1.1 Java程序执行过程

1.2 程序计数器作用

1.3 程序计数器特点

1.3.1 线程私有

1.3.2 不存在内存溢出OutOfMemoryError

二、虚拟机栈

2.1 定义

2.2 特点

2.3 虚拟机栈内存什么

2.4 栈内存溢出

2.4.1 栈帧过多内存溢出

2.4.2 栈帧过大内存溢出

2.5 线程诊断

三、本地方法栈

3.1 与虚拟机栈对比

3.2 Native Method

3.2.1 什么是Native Method

3.2.2 为什么调用Native Method

3.3 JVM时如何跑一个本地方法的

四、堆

4.1 堆(heap)的概述

4.2 堆内存结构

4.3 分代

4.3.1 分代的概念

4.3.2 分代结构

五、方法区

5.1 方法区、堆、栈的配合关系

5.2 方法区概述

5.3 方法区的演进

5.3.1 永久代

5.3.2 元空间

5.4 方法区内部结构

 5.4.1 具体分析

5.4.2 类型信息

5.4.3 域(Field)(属性)信息

5.4.4 方法(Method)信息

5.4.5 non-final的类变量

5.4.6 全局常量(static+final)

5.5 常量池

5.5.1 什么是常量池

5.5.2 常量池有什么用

5.5.3 方法区使用举例

5.5.4 运行时数据区的详细结果

5.5.5 常量池里有什么

5.6 一些问题

5.6.1 为什么要把永久代改为元空间

5.6.2 String Table为什么要放到堆区

5.7 方法区的垃圾回收


文章内容系个人学习笔记、网课截图和笔记、站内博客资料,如有冒犯,请联系我。

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应用以外的繁琐的细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值