java虚拟机成神之路 - JVM内存区域与内存溢出异常

**程序计数器**:在循环、跳转、异常处理等情况发生时,经常会产生字节码行号变动。 可以看做程序计数器,告诉当前线程下一步要执行的字节码的行号。它是线程私有的,每个线程都有自己独立的程序计数器。在多线程的时候,经常会进行线程的切换,在线程切换后,帮助线程找到要执行的位置。

**虚拟机栈**: 线程私有。每个方法在被执行的时候,虚拟机栈都会创建一个栈帧,栈帧中存放局部变量表、操作数栈、方法出口、动态连接等信息。局部变量表中存放基本数据类型、引用类型和returnAddress(指向一条字节码指令的地址),以变量槽(slot)的方式来存储,其中64位long和double类型占两个槽,其余只占用一个槽。虚拟机栈中线程申请的栈深度大于虚拟机所允许的深度会发生StackOverflowError。虚拟机栈中当栈扩展时无法申请到足够的内存会发生OutOfMemoryError(OOM)(HotSpot虚拟机栈容量不能动态扩展)

**本地方法栈**:虚拟机栈为虚拟机执行Java方法(字节码)服务,而虚拟机栈为虚拟机执行本地方法服务。

Hotspot虚拟机已经将虚拟机栈和本地方法栈合而为一了。

**堆**:线程共享,存放对象、数组以及其它一些数据结构。几乎所有的实例对象都在堆中存放。在分配内存时可以划分出多个线程私有的缓冲区,提升运行效率。hotspot可以动态扩展堆的大小。如果在堆中没有内存完成实例分配会报OutOfMemoryError。

- `-Xms`:指定JVM的初始堆内存大小。例如,`-Xms512m`表示将初始堆内存设置为512MB。
- `-Xmx`:指定JVM的最大堆内存大小。例如,`-Xmx1024m`表示将最大堆内存设置为1GB。
- `-Xss`:指定线程堆栈的大小。默认情况下,每个线程的堆栈大小是1MB。例如,`-Xss256k`表示将线程堆栈大小设置为256KB。

**方法区**:线程共享。用于存放已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据

**运行时常量池**:是方法区的一部分,class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table) 

#### Hotspot虚拟机

当虚拟机遇到字节码new指令时,会先查找常量池中有没有该对象,如果常量池中没有该对象就执行类加载过程。类检查通过后加载对象的内存,假设内存是按区域划分的,空闲内存在指针的一边,使用过的内存在指针的另一边,挪动指针来分配内存大小,称为指针碰撞的方式。还有一种为空闲列表,假设内存划分是不规整的,这时就维护一个列表来记录哪些内存块是可用的,内存块的大小大于对象实例就分配,并更新表。

还需考虑内存并发情况下的线程安全问题,正在给A分配内存时,B又过来动用原先的指针。解决一是采用CAS配上失败重试的方式保证更新操作的原子性。解决二是,为每个线程配置一个缓冲区,哪个线程要分配就在哪个线程的缓冲区上分配。内存分配完还要将对象赋0值,这样就可以使对象不被赋初始值时就能被使用。

对象在堆内存中的布局可划分为:对象头(存储对象自身运行时的数据)、实例数据(为了确定该对象是哪个类的实例)、对齐填充(该对象大小必须是8字节的整数倍)

引用去定位的方式:句柄池访问和直接指针访问

引用计数算法:在对象中添加一个引用计数器,每当有一个地方 引用它时,计数器值就加一;当引用失效时,计数器值就减一。两个对象已 经不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为零,引用计数算法也 就无法回收它们

可达性分析算法:来判定对象是否存活的。这个算法的基本思路就是通过 一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过 程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连, 或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值