万字吐血总结JVM知识点

前言:这一年前前后后把《深入理解JVM》看了好几遍,最近把里面所有的知识点整理如下,供大家一起学习。

第二章 Java内存区域与内存溢出异常

一、运行时数据区域
1.程序计数器:线程私有,是一块较小内存空间,可以看作当前线程的执行字节码的行号指示器。CPU分配给A线程的时间片用完,线程挂起,程序计数器记录当前线程执行的字节码指令地址。线程切换回来,再次获取CPU时间片,依靠程序计数器保存的字节码指令地址继续执行程序。
2.虚拟机栈:线程私有,生命周期和线程一样。Java方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈等信息,每一个方法的调用到完成的过程都对应一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表存放了编译器可知的基本数据类型,对象引用和returnAddress类型。局部变量表所需的内存空间在编译期间完成分配,进入一个方法时这个方法需要在虚拟机栈中分配多大的局部变量空间是确定的。
3.本地方法栈:发挥的作用和虚拟机栈类似,虚拟机栈为java方法服务,本地方法栈为虚拟机使用到的native方法服务。
4.Java堆:是java虚拟机管理的内存中最大的一块。java堆线程共享,所有的对象实例和数组被分配到堆内存中。Java堆是垃圾收集器管理的主要区域,可以叫做GC堆。内存回收的角度可以分为新生代、老年代。内存分配的角度,共享的java堆还可以划分出多个线程私有的内地内存。
这里写图片描述
5.方法区:与Java堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息 、常量、静态变量等数据。方法区和Java堆一样不需要连续的内存并且可以选择固定大小或是可扩展。方法区的垃圾回收目标主要是对常量池的回收与类型的卸载,垃圾收集频率很低。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
6.运行时常量池是方法区的一部分:Class文件除了有类的版本、字段、方法、接口的信息外,还有编译期生成的各种字面量和符号引用,这部分内容在类加载后会进入方法区的运行时常量池中存放。运行时常量池具有动态性,运行期间也可能将新的常量放入池中。

二、对象创建、对象的内存布局、对象的访问定位
1.对象的创建:虚拟机遇到一条new指令,先检查这个指令的参数是否能在方法区的运行时常量池定位到一个符号引用,检查符号引用代表的class类是否被加载,解析和初始化。若没有,那么先执行相应地类加载过程。
类加载后在java堆中为对象实例分配内存空间,对象内存空间大小在类加载时确定好。分配的策略分两种。如果java堆的内存是规整的,所有用过的内存放在一边,空闲内存放在一边,中间由一个指针作为分界器。分配内存就是将指针从使用过的内存往空闲内存区划一个分配空间的大小区域。这种叫做“指针碰撞”。若java堆使用内存和空闲内存相互交错,虚拟机就维护一个“空闲列表”记录哪些内存块是空闲。分配内存时,从空闲列表里查找差不多大小的内存块存储对象实例,并且更新空闲列表。哪种分配方式的使用由垃圾收集器的不同类型来决定。
还需要考虑并发情况下创建对象的线程安全问题。如果A线程给A对象分配内存,指针还没来得及修改,B线程使用原来的指针位置给B对象分配内存,导致内存分配出问题。JVM解决的方法是使用CAS操作来保证更新指针位置的原子性。另一种是java堆里每个线程都有线程私有的分配缓冲区,对象分配在分配缓冲区中分配,相互独立。
对象实例分配完成后需要将分配到的内存空间初始化零值。这样保证实例字段不赋初始值也可以使用。

接着虚拟机会对对象头进行设置。对象头包含markword,和指向对象类型数据的指针。markword里面包含了对象的锁状态,hashcode和分代年龄等。
这样一个新的对象产生了。

2.对象的内存布局
对象在内存中存储分为3块区域:对象头、实例数据和对齐填充。
对象头分为俩个部分,一个是含有锁状态,对象hashCode,分代年龄 ,是否是偏向锁信息的markword,另一个是指向对象类型数据的指针。如果对象是数组,对象头里还需要有一块记录数组长度的内存。
实例数据部分是对象真正存储的有效信息,也是各种类型的字段内容。
对齐填充起着占位符的作用,因为JVM要求对象的大小必须是8字节的整数倍,对象头恰好是8字节的整数倍,若实例数据部分没有对齐则需要通过对齐填充来补全空间。

3.对象的访问定位
java程序通过虚拟机栈上的reference引用操作堆上的具体对象。对象访问方式有俩种:
句柄访问:java堆上划分一块内存作为句柄池,虚拟机栈的reference上存的是句柄池的地址,句柄池存有分别指向对象实例数据和类型数据的指针。好处:对象在垃圾回收时频繁移动,只需要修改句柄池中实例数据地址,reference不需要修改。但是访问效率慢,需要俩次指针定位。
直接指针访问:虚拟机栈的reference里存有指向java堆中具体实例对象的地址,对象头里存储指向类型数据的地址。指针访问速度快,一次定位。

二、OutOfMemoryError异常,内存溢出异常
(堆 heap 栈 stack 新生代 new generation 老年代 tenured generation)
1.内存溢出(OutOfMemory):程序在申请内存的时候,没有足够的内存空间供其使用&

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值