【Java】JVM内存相关笔记

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。


程序计数器:由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为"线程私有"的内存。

Java虚拟机栈 :虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

经常有人把Java内存区域笼统地划分为堆内存和栈内存,实际的内存区域划分要比这更复杂。不过这种划分方式的流行也间接说明了程序员最关注的、与对象内存分配关系最密切的区域是"堆"和"栈"两块。其中,"栈"通常就是指这里讲的虚拟机栈,或者更多的情况下只是指虚拟机栈中局部变量表部分。

局部变量表存放了编译期可知的各种Java虚拟机基本数据类型、对象引用。

本地方法栈:与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的本地方法服务。

Java堆 :是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里"几乎"所有的对象实例都在这里分配内存。在《Java虚拟机规范》中对Java堆的描述是:"所有的对象实例以及数组都应当在堆上分配"。

Java堆是垃圾收集器管理的内存区域,并且存储的都只能是对象的实例,将Java堆细分的目的只是为了更好地回收内存,或者更快地分配内存。

方法区:与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。虽然《Java虚拟机规范》中把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫作"非堆",目的是与Java堆区分开来。《Java虚拟机规范》对方法区的约束是非常宽松的,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,甚至还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域的确是比较少出现的。

在Java中,控制内存的权力交给了Java虚拟机,所以我们无法直接在程序中获取创建的变量的内存地址,因此在学习过程中我们可以通过变量的哈希值来显式的展示变量在Java虚拟机中的位置,Java根据哈希值最终分配到计算机的内存中。

例如,对象实例在操作过程中的内存分配可以如此表现

java 复制代码
TestOne testOne=new TestOne();
testOne.setId(123);
testOne.setUid(666);
System.out.println("uid="+testOne.getUid());
System.out.println("uid->"+(String.valueOf(testOne.uid).hashCode()));
System.out.println("id="+testOne.getId());
System.out.println("id->"+(String.valueOf(testOne.id).hashCode()));

testOne.setId(testOne.getUid());
System.out.println("uid="+testOne.getUid());
System.out.println("uid->"+(String.valueOf(testOne.uid).hashCode()));
System.out.println("id="+testOne.getId());
System.out.println("id->"+(String.valueOf(testOne.id).hashCode()));
相关推荐
DCTANT18 分钟前
【原创】国产化适配-全量迁移MySQL数据到OpenGauss数据库
java·数据库·spring boot·mysql·opengauss
sealaugh3220 分钟前
aws(学习笔记第四十八课) appsync-graphql-dynamodb
笔记·学习·aws
Touper.28 分钟前
SpringBoot -- 自动配置原理
java·spring boot·后端
黄雪超37 分钟前
JVM——函数式语法糖:如何使用Function、Stream来编写函数式程序?
java·开发语言·jvm
ThetaarSofVenice44 分钟前
对象的finalization机制Test
java·开发语言·jvm
望获linux2 小时前
【实时Linux实战系列】CPU 隔离与屏蔽技术
java·linux·运维·服务器·操作系统·开源软件·嵌入式软件
JosieBook2 小时前
【Java编程动手学】使用IDEA创建第一个HelloJava程序
java·开发语言·intellij-idea
Thomas_YXQ2 小时前
Unity3D DOTS场景流式加载技术
java·开发语言·unity
summer夏1232 小时前
2025.07 做什么
java·android studio
钢铁男儿3 小时前
C# 委托(调用带引用参数的委托)
java·mysql·c#