Java虚拟机(JVM):第二幕:自动内存管理 - Java内存区域与内存溢出异常
前言:Java与C++之间有一堵高墙,主要是有内存动态分配和垃圾收集技术组成的。墙外的人想要进来,墙内的人想要出去。
一、运行时数据区域
JVM在执行Java程序时,会将其管理的内存划分为若干个不同的数据区域。

1、是程序计数器,一个处理器一般只会执行一条线程的指令。为了线程切换后恢复到正确的执行位置,每一条线程都需要一个独立的程序计数器,每一个计数器互相不影响,独立存储,最重要的一点事,此类内存区域属于“线程私有”的内存。
2、接下来介绍,Java虚拟机栈也是线程私有的,虚拟机栈指的是Java方法执行的线程内存模型。经常有人将Java内存区域笼统的划分为“堆内存”和“栈内存”。这里的“栈内存”指的是Java虚拟机栈,但是确切的说是,虚拟机栈中的局部变量表部分。局部变量表存储了各种基本的数据类型,存储空间以局部变量槽表示,关于局部变量槽所占用的比特数量,有虚拟机决定。
3、其次是本地方法栈:为虚拟机用到的本地方法服务,有些虚拟机会将本地方法栈和虚拟方法栈合并(HotSpot:关于它的解释,见以前的博客)。
4、Java堆:Java堆是虚拟机所管理的内存中的最大的一部分,被所有线程所共享,同时也是垃圾收集器管理的内存区域,从分配内存的角度来看,Java堆可以分出多个线程私有的分配缓冲区,来提高对象分配时的效率。PS:根据规定,Java堆在物理上可以不连续,但是在逻辑上是连续的。
5、方法区:是一个线程共享的内存区域,用来存储已经被虚拟机加载的类型信息、常量、静态变量等数据。
6、运行时常量池:方法区的一部分,Class文件中除了常见的描述信息外,还有一项信息是常量池表,用来存放编译期生成的高中字面量和符号引用,常量池表的内容在类引用之后存放到方法区中的运行时常量池中。另外一个特征是动态性,可以在运行期间将新的常量加入池中。
7、直接内存:使用native函数库直接分配堆外内存,通过存放在Java堆中的对象作为这一部分内存的引用进行操作。
二、HotSpot虚拟机对象探秘
在第一部分,学习了内存存放什么,但是对于如何创建以及如何访问等,存在着盲区,这里采用最常见的虚拟机Hotspot和最常用的内存区域Java堆。来深入探讨一些虚拟机内部的神秘世界。
2.1、对象的创建
1、当遇到new命令时,检查指令的参数是否能在常量池中正确定位符号的引用,检查符号代表的类是否被加载、解析和初始化过。如果没有执行操作2。
2、类加载检查通过后,为新生对象分配内存(大小确定),Java堆中的内存必定存在已经分配和未被分配的,所以分配方式引入“指针碰撞”的方式进行分配内存[Java堆内存是规整的],如果不规整的话,需要采用“空闲列表”的方式,来分配内存。
3、除了划分可用空间之外,对象在虚拟机创建的行为是频繁的,经常发生“线程安全”问题,解决方法:1、保证分配空间的原子性。2、预先分配内存,此方式为“本地线程分配缓冲”:哪家线程要分配内存,就在哪家的本地缓冲区中分配,只有这一次的本地缓冲区用完之后,采用分配新的,同时进行同步锁定。
4、分配到的内存空间初始化为零值,这样的操作,对应到Java代码中为:不用赋予初始值就可以使用。
5、所有的信息都要存储到对象头中。
6、虽然上述操作介绍完了,但是仅此还是不够的。对象构建需要的其他资源也没有弄好。
2.2、对象的内存布局
HotSpot虚拟机中,对象在堆内存中的存储布局主要分为三个部分:对象头、实例数据、对齐填充。
首先介绍一下对象头,对象头主要分为两部分,第一部分是用于存储对象自身的运行时数据,包括各类的标识元数据信息,为了更好的存储数据,所以将此设计为动态定义的数据结构。第二部分是类型指针,也就是对象指向它的类型元数据的指针,查找对象的元数据信息并不一定经过对象本身。
实例数据:用来存储对象的真正有效的信息,也就是我们在程序代码中定义的各种类型的字段内容。
对齐填充:仅仅是占位符的作用,因为自动内存管理系统要求对象的起始地址必须是8字节的整数倍,所以,对于对象实例数据没有对齐的部分,就需要通过填充来对齐。
2.3、对象的访问定位
因为在Java程序中没有被定义,所以具体的访问方式需要在虚拟机中去实现,主流的访问方式有使用句柄和直接指针两种。
1、使用句柄:这个像是引入了“中间商”,Java堆中划出一块内存来当做句柄池。
2、使用直接访问:reference存储的直接就是对象地址。
两者只能说是各有优劣,句柄最大的好处是,当对象被移动是,只会修改句柄中的实例数据指针,而reference本身不需要修改。直接指针最大的优点就是访问速度更快。本文以HotSpot为主,它采用的是直接指针访问的方式,但是如果从整个软件开发的范围来看,使用句柄来访问显得更加的优秀。
三、实战:OutOfMemoryError 异常
1、Java堆溢出:这种异常方式是最为常见的内存溢出情况,解决方法在于:通过内存映像分析工具 对Dump出来的堆转储快照进行分析。存在内存泄漏和内存溢出两种。
2、虚拟机栈和本地方法栈溢出:
3、方法区和运行时常量池溢出:运行时常量池是方法区的一部分.
4、本地直接内存溢出‘:直接内存的大小可以通过参数来制定。
Java虚拟机(JVM):第二幕:自动内存管理 - Java内存区域与内存溢出异常的更多相关文章
- JVM内存管理------JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义
前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine ,既然是虚拟机, ...
- Java虚拟机------JVM内存区域
JVM内存区域运行时数据区域分为两种: JVM内存区域 运行时数据区域分为两种: 线程隔离的数据区: 程序计数器 Java虚拟机栈 本地方法栈 所有线程程共享的数据区: Java堆 方法区 JVM 内 ...
- java虚拟机 jvm 出入java栈 栈空间内存分配
java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关.线程最基本的执行行为就是函数的调用.每次函数调用其实是通过java栈传递数据的. 数据结构中 ...
- 如何设置Java虚拟机JVM启动内存参数
Tomcat默认的Java虚拟机JVM启动内存参数大约只有64MB或者128MB,非常小,远远没有利用现在服务器的强大内存,所以要设置Java虚拟机JVM启动内存参数.具体设置方法为: Tomcat修 ...
- 深入理解java虚拟机_第二章_读书笔记
1.本章内容目录: 概述 运行时数据区域 程序计数器 java虚拟机栈 本地方法栈 java堆 方法区 运行时常量池 直接内存 HotSpot虚拟机对象探秘 对象的创建 对象的内存布局 对象的访问定位 ...
- Java虚拟机(JVM)知多少
本文大量参考:https://www.cnblogs.com/lfs2640666960/p/9297176.html 概述 JVM是JRE的一部分.它是一个虚构出来的计算机,是通过在实际的计算机上仿 ...
- 深入理解java虚拟机JVM(下)
深入理解java虚拟机JVM(下) 链接:https://pan.baidu.com/s/1c6pZjLeMQqc9t-OXvUM66w 提取码:uwak 复制这段内容后打开百度网盘手机App,操作更 ...
- Java虚拟机JVM相关知识整理
Java虚拟机JVM的作用: Java源文件(.java)通过编译器编译成.class文件,.class文件通过JVM中的解释器解释成特定机器上的机器代码,从而实现Java语言的跨平台. JVM的体系 ...
- 深入理解java虚拟机JVM(上)
深入理解java虚拟机JVM(上) 链接:https://pan.baidu.com/s/1c6pZjLeMQqc9t-OXvUM66w 提取码:uwak 复制这段内容后打开百度网盘手机App,操作更 ...
随机推荐
- MyBatis-plus乐观锁
什么是乐观锁呢?为什么要使用这个功能?这个功能能做什么呢?如何使用这个? 1.乐观锁( Optimistic Locking ) 是相对悲观锁而言的,乐观锁是假设认为数据一般情况下不会造成冲突,所以在 ...
- 从头学Java17-Lambda表达式
Lambda表达式 这一系列教程,旨在介绍 lambda 的概念,同时逐步教授如何在实践中使用它们. 回顾表达式.语句 表达式 表达式由变量.运算符和方法调用组成,其计算结果为单个值.您已经看到了表达 ...
- Windows系统使用Nginx部署Vue
Nginx是什么? Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 ,同时也提供了IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的R ...
- Istio 入门(五):访问控制和流量管理
本教程已加入 Istio 系列:https://istio.whuanle.cn 目录 4, 流量管理 基于版本的路由配置 基于 Http header 的路由配置 故障注入 两种故障注入 比例分配流 ...
- 使用Locust进行性能测试
当涉及到评估应用程序或服务的性能时,Locust是一个功能强大且易于使用的开源工具.本文将介绍Locust的基本概念和使用方法. 什么是Locust? Locust是一个用于编写.运行和分析负载测试的 ...
- typedef和define有什么区别
typedef 和define 都是替一个对象取一个别名,以此增强程序的可读性,区别如下: 使用不用 define 定义后面不用加分号,并且它的别名在对象的前面 typedef需要加分号,并且它的别名 ...
- MAUI Blazor 显示本地图片的新思路
前言 好久没写文章了,水一篇 关于MAUI Blazor 显示本地图片这个问题,有大佬发过了. 就是 token 大佬的那篇 Blazor Hybrid (Blazor混合开发)更好的读取本地图片 主 ...
- JDV背后的技术-助力618
一.项目介绍 JDV(可视化大屏)是京东内部搭建可视化大屏的数据工具平台,内置10+种模版特效,40+种风格各异的图表.导航等组件.与集团其他数据工具打通,支持一站式.自助化.拖拽式搭建大屏,实现数据 ...
- 糟了糟了,总部被SD画完都Q了,这篇深入浅出贴助你早日实现Stable Diffusion自由
我也不想标题党,可乐高积木版的总部大楼就是好萌啊! 我是憨憨,一个不会画画的设计师.过去半年里,AI绘画曾经多次引爆公众讨论,网络上那些精致的二次元同人插画.堪比真人的AI穿搭博主.打破次元壁的赛博C ...
- papricice
2023-07-14 题目 题目传送门 题目大意 给定一个 \(n\) 个点的树,这 \(n\) 个点编号为 \(1\) 到 \(n\). 现在要选择断掉两条边,会形成三个连通块,假设这三个连通块内的 ...