一、 概述

在虚拟机自动内存管理机制下,不容易出现内存泄漏和内存溢出问题,但是一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那排查错误、修正问题将会成为一项异常艰难的工作。

二、运行时数据区域

1 程序计数器

Java虚拟机运行时数据区:

程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。改变计数器的值来选取下一条要执行的字节码指令(和计算机CPU一样),各条线程之间的计数器互不影响,独立存储,是“线程”私有的内存。

2 Java虚拟机栈

Java虚拟机栈(Java Virtual Machine Stack)也是线程私有的,它的生命周期与线程相同。每个方法执行的时候,java虚拟机会同步创建一个栈帧,用于存储局部变量表,操作数栈,动态连接,方法出口等信息,每个方法执行的过程,对应一个栈帧在虚拟机中入栈和出栈的过程。

局部变量表存放编译期可知的各种基本数据类型,引用类型和returnAddress类型(指向了一条字节码指令的地址)。

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果Java虚拟机栈容量可以动态扩展[2],当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。

3 本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,本地方法栈则是为虚拟机使用到的本地(Native)方法服务。

4 Java堆

Java堆(Java Heap)是虚拟机所管理的内存中最大的一块,是被所有线程共享的,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。

Java堆是垃圾收集器管理的内存区域,因此一些资料中它也被称作“GC堆”,J堆中经常会出现“新生代”“老年代”“永久代”“Eden空间”“From Survivor空间”“To Survivor空间”等名词,这些区域划分仅仅是一部分垃圾收集器的共同特性或者说设计风格而已,而非某个Java虚拟机具体实现的固有内存布局。

5 方法区

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

6 运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

7 直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。

三、HotSpot虚拟机对象探秘

1 对象的创建

(1)当Java虚拟机遇到一条字节码new指令时,先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程

(2)在类加载检查通过后,虚拟机将为新生对象分配内存。由Java堆是否规整决定选择哪种分配方式:

  1. 把指针向空闲空间方向挪动一段与对象大小相等的距离,称为“指针碰撞”
  2. 内存不规整,已被使用的内存和空闲的内存相互交错在一起,虚拟机必须维护一个列表来记录上哪些内存块是可用的,分配时从列表中找一块足够大的空间划分给对象实例,并更新列表上的记录,称为“空闲列表”

(3)内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值。

(4)对对象进行必要的设置。

2 对象的内存布局

对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

(1)对象头:

包括两类信息。分别是:

a.用于存储对象自身的运行时数据,官方称它为“Mark Word”。

b.类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例。

(2)实例数据

是对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容。

(3)对齐填充

并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。

3 对象的访问定位

Java程序会通过栈上的reference数据来操作堆上的具体对象,对象访问方式由虚拟机实
现而定,主流的访问方式主要有使用句柄和直接指针两种:

(1)使用句柄访问

Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息。

(2)使用直接指针访问

Java堆中对象的内存布局就必须考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问的开销。最大的好处是速度更快,它节省了一次指针定位的时间开销。

四、实战:OutOfMemoryError异常

【代码实践,没有跟着做,记录一下要点吧】

1 Java堆溢出

2 虚拟机栈和本地方法栈溢出

1)如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
2)如果虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出
OutOfMemoryError异常。

3 方法区和运行时常量池溢出

在JDK 8以后,HotSpot还是提供了一些参数作为元空间的防御措施,主要包括:
·-XX:MaxMetaspaceSize:设置元空间最大值,默认是-1,即不限制,或者说只受限于本地内存大小。
·-XX:MetaspaceSize:指定元空间的初始空间大小,以字节为单位,达到该值就会触发垃圾收集进行类型卸载,同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过-XX:MaxMetaspaceSize(如果设置了的话)的情况下,适当提高该值。
·-XX:MinMetaspaceFreeRatio:作用是在垃圾收集之后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率。类似的还有-XX:Max-MetaspaceFreeRatio,用于控制最大的元空间剩余容量的百分比。

4 本机直接内存溢出

直接内存(Direct Memory)的容量大小可通过-XX:MaxDirectMemorySize参数来指定,如果不去指定,则默认与Java堆最大值(由-Xmx指定)一致。

五、 本章小结

本章只是讲解了各个区域出现内存溢出异常的原因。

先看书记录一下要点,之后看视频的时候会进行补充记录。
(如果能坚持到看视频的话……)

《深入理解JAVA虚拟机》周志明 第三版 - 第二章 JAVA内存区域与内存溢出异常相关推荐

  1. 《深入理解JAVA虚拟机》周志明 第三版 - 第一章 走近JAVA

    1.java优点 一次编写.到处运行:相对安全的内存管理和访问机智:热点代码检索和运行时编译以及调优:完善的API,多样的第三方类库. 2.java体系[广义] 3.Java发展史 发展时间线图如下: ...

  2. 深入理解java虚拟机第一第二部分(周志明第三版)

    文章目录 深入理解java虚拟机(周志明第三版) 第一部分.Java的前世今生和未来展望 1.1.概述 1.2.java技术体系 1.3.Java发展史(只记录比较重要的) 1.4.Java虚拟机家族 ...

  3. 深入理解Java虚拟机(周志明第三版)- 第十一章:后端编译与优化

    系列文章目录 第一章: 走近Java 第二章: Java内存区域与内存溢出异常 第三章: Java垃圾收集器与内存分配策略 从计算机程序出现的第一天起,对效率的追逐就是程序员天生的坚定信仰,这个过程犹 ...

  4. 深入理解Java虚拟机(周志明第三版)- 第十三章:线程安全与锁优化

    系列文章目录 第一章: 走近Java 第二章: Java内存区域与内存溢出异常 第三章: Java垃圾收集器与内存分配策略 并发处理的广泛应用是Amdahl定律代替摩尔定律[1]成为计算机性能发展源动 ...

  5. 深入理解Java虚拟机(周志明第三版)- 第十二章:Java内存模型与线程

    系列文章目录 第一章: 走近Java 第二章: Java内存区域与内存溢出异常 第三章: Java垃圾收集器与内存分配策略 并发处理的广泛应用是Amdahl定律代替摩尔定律成为计算机性能发展源动力的根 ...

  6. 深入理解Java虚拟机(周志明第三版)- 第八章:虚拟机字节码执行引擎

    系列文章目录 第一章: 走近Java 第二章: Java内存区域与内存溢出异常 第三章: Java垃圾收集器与内存分配策略 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言 ...

  7. 《深入理解JAVA虚拟机》周志明 第三版 - 第四章 虚拟机性能监控、故障处理工具

    4.1 概述 恰当地使用虚拟机故障处理.分析的工具可以提升我们分析数据.定位并解决问题的效率. 4.2 基础故障处理工具 JDK的bin目录中有java.exe.javac.exe这两个命令行工具,还 ...

  8. 《深入理解Java虚拟机》-周志明 -第3版-第一章摘记

    第一章讲了java的发展和变迁,在章节末作者讲到了编译openjdk源码和调试源码 java发展史 java的诞生起因史1991年4月,James Gosling博士领导的绿色计划(Green Pro ...

  9. 对话《深入理解Java虚拟机》作者周志明:电竞选手成为Java大神之路

    声明:本文由"阿里云MVP团队"原创,转载经"阿里云开发者社区"授权.原文标题:<职业电竞选手的Java大神路:对话阿里云MVP周志明>. 销售超过 ...

最新文章

  1. CTFshow php特性 web148
  2. Python正则表达式之零宽断言(4)
  3. 陕西师范大学计算机科学学院公寓楼,陕西师范大学计算机科学学院简介
  4. 记一次引入Elasticsearch的系统架构实战
  5. C语言试题八十八之实现选冒泡排序算法
  6. centos7中,mysql连接报错:1130 - Host ‘118.111.111.111’ is not allowed to connect to this MariaDB server...
  7. where 1=1会影响索引吗_MySQL之InnoDB存储引擎:索引的使用
  8. 4个常用的计算机应用软件,信息技术应用--常用计算机工具软件4常用工具软件单元四.pdf...
  9. 公钥、私钥和数字签名是什么
  10. 2011年国庆老家记录
  11. 如何下载微信开发者工具?
  12. 一篇很好的大牛面试经验
  13. 金山数据恢复 2.0
  14. HTML教程: 网页字体的设置浅谈
  15. 全球及中国生物农药行业投资状况与十四五运行态势研究报告2022版
  16. 安卓手机(荣耀/vivo)下载以及安装Charles证书
  17. 【go1.18】error obtaining VCS status: exit status
  18. Win10 卸载 Cortana
  19. 浅谈垂直腔面发射激光器的设计原则
  20. 访问局域网另外一台电脑虚拟机中CentOS7

热门文章

  1. 解决模拟器方向键无法使用问题
  2. 3dsmax2014插件开发之环境搭建
  3. 通过公众号迁移快速开通留言功能方法
  4. linode购买服务器
  5. VScode VSC Netease Music(网易云音乐)插件
  6. java中File的总结
  7. 拾人牙慧,浅记一些C++的类
  8. 如何让应用支持64位 Android,Sailfish OS 4.1终于拥抱64位 Android10应用支持API等级
  9. Apache解析漏洞CVE-2017-15715、apache_parsing_vulnerability、CVE-2021-40438 vulhub复现分析
  10. iphone相册储存空间已满_iPhone老提示储存空间已满的具体处理操作