Java虚拟机

本文详细介绍了Java内存管理的关键概念,包括Java堆、Java栈、方法区和指令计数器的功能与工作原理。探讨了对象分配内存的不同方法,如指针碰撞法和空闲列表法,以及在多线程环境下如何解决内存分配问题。同时,文章还讲解了对象在内存中的布局,包括对象头、实例数据和对齐填充的具体细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

Java堆

Java堆是被所有线程共享的内存区域,主要用于存放对象实例。为对象分配内存就是把一块确定大小的内存从堆内存中划分出来,通常有两种方法实现:
1、指针碰撞法:已分配的内存和空闲内存分别在一个指针的两侧,需要分配内存时,把指针往空闲的一端移动与对象大小相等的距离。
2、空闲列表法:上个方法的环境几乎不存在,JVM一般都是维护一个列表,列表中记录可用的内存块信息,当分配操作发生时,从列表上找到一个足够大的内存块分配给对象实例,并更新列表上的记录。

在创建对象时还要考虑多线程的问题,有两种解决方案:
1、采用CAS(Compare And Swap)操作保证数据更新的原子性。
2、把内存分配的行为按照线程进行划分,在不同的空间中进行,每个线程在Java堆中预先分配一个内存块,称为本地线程分配缓冲(TLAB)。

Java栈

Java栈是线程私有的,每个线程对应一个Java栈,每个线程在执行方法时会创建一个对应的栈帧,栈帧负责存储局部变量表、操作数栈、动态链接和方法返回地址等信息。每个方法的调用过程,相当于栈帧在Java栈的入栈和出栈过程。
在这里插入图片描述

局部变量表

用于存放方法参数和方法内部定义的局部变量,大小在编译期间已经确定不会改变。以变量槽(Slot)为最小存储单位,每个slot能够存放一个boolean、byte、char、shot、int、float、reference和returnAddress类型的32位数据,64位的数据会以高位对齐的形式占用两个连续的槽。

方法区

方法区和Java堆都是线程共享的,用于存放已被虚拟机加载的类信息、常量、静态变量和即时编辑器编译后的代码数据。
运行时常量池也是方法区的一部分,用于存放编译期间生成的各种字面常量和符号引用。

指令计数器

指令计数器是线程私有的,每个线程都有独立的指令计数器,计数器记录着虚拟机正在执行的字节码指令的地址,分支、循环、跳转、异常处理和线程恢复等操作都依赖于计数器。如果是native方法则为空。

对象组成的内存布局

对象在内存中分为三块区域:对象头,实例数据和对齐填充
1、对象头
包括两部分信息:运行时数据和类型指针,如果对象是一个数组,还需要一块用于记录数组长度的数据。
运行时数据: 包括HashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID和偏向时间戳等。
类型指针: 指向该对象的类元数据,通过这个指针可以知道是哪个类的实例。
2、实例数据
就是在程序代码中所定义的各种类型的字段,包括从父类继承的,这部分的存储顺序会受到虚拟机分配策略和字段在源码中定义顺序的影响。
3、对齐填充
自动内存管理要求对象的起始地址必须是8字节的整数倍,即对象的大小必须是8的整数倍,因此不够的时候会自动通过对齐填充补全。
参考资料:
https://www.jianshu.com/p/eaef248b5a2c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值