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,操作更 ...
随机推荐
- 基于drawio构建流程图编辑器
基于drawio构建流程图编辑器 drawio是一款非常强大的开源在线的流程图编辑器,支持绘制各种形式的图表,提供了Web端与客户端支持,同时也支持多种资源类型的导出. 描述 在我们平时写论文.文档时 ...
- ArcPy批量对大量遥感影像相减做差
本文介绍基于Python中ArcPy模块,对大量栅格遥感影像文件批量进行相减做差的方法. 首先,我们来明确一下本文的具体需求.现有一个存储有多张.tif格式遥感影像的文件夹,其中每一个遥感影像 ...
- h2database BTree 设计实现与查询优化思考
h2database 是使用Java 编写的开源数据库,兼容ANSI-SQL89. 即实现了常规基于 BTree 的存储引擎,又支持日志结构存储引擎.功能非常丰富(死锁检测机制.事务特性.MVCC.运 ...
- 深入浅出synchronized的原理与源码
深入浅出synchronized的原理与源码 1.java对象头关于锁的标识 1.对象头 // 32 bits: // -------- // hash:25 ------------>| ag ...
- Spring Loaded代码热更新实践和原理分析
1.引言 开发者在编码效率和快速迭代中的痛点场景包括: 修改代码后,需要频繁重启应用,导致开发效率低下: 实时调试时,不能立即看到代码修改的结果: 大型项目中,重启的时间成本较高. 针对这些问题,本文 ...
- 通用权限系统-Dozer对象转换
Dozer对象转换 介绍 Dozer 是一个 Java Bean 到 Java Bean 的映射器,它可以递归地将数据从一个对象复制到另一个.通常情况下,这些Java Beans将是不同的复杂类型. ...
- 【从0开始编写webserver·基础篇#03】TinyWeb源码阅读,还是得看看靠谱的项目
[前言] 之前通过看书.看视频和博客拼凑了一个webserver,然后有一段时间没有继续整这个项目 现在在去看之前的代码,真的是相当之简陋,而且代码设计得很混乱,我认为没有必要继续在屎堆上修改了,于是 ...
- CF1829H Don't Blame Me题解
题意: 给定一个长度为 \(n\) 的数组,选择它的一个子序列(不一定要连续的),问有多少种选法使得它们 AND 的值的二进制表示法中有 \(k\) 个 \(1\). 思路: 这个题就是一个简单的 D ...
- 【阅读笔记】超分之LANR-NLM算法
论文信息 [Single Image Super-Resolution via Locally Regularized Anchored Neighborhood Regression and Non ...
- 因为一条DDL,差点搞挂整个系统,这次真的长了教训
有一次在线上提了一个sql变更,就是下面这条, -- 修改字段的数据类型由varchar(500)变更为text ALTER TABLE t MODIFY COLUMN name text; 提完之后 ...