JVM内存模型
-
java内存中变量的存储位置
- 局部变量:方法中的局部变量存在于栈内存。每当程序调用一个方法时,系统都会为该方法建立一个方法栈,所在方法中声明的变量就放在方法栈中,方法结束系统会销毁该方法栈,在该方法中声明的变量随着栈的销毁而结束,这就是局部变量只能在方法中有效的原因。
-
成员变量:对象实例的引用存储在栈内存中,对象实例存储在堆内存中。所以,对象中声明的成员变量存储在堆中。(成员变量不会随着某个方法执行结束而销毁)
-
静态变量:类中的静态变量存在 Java 内存区域的方法区。方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量,即编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。
-
本地方法栈和JVM栈的区别
-
JVM运行时数据区域有哪些?
- 堆区:堆主要存放Java在运行过程中new出来的对象,凡是通过new生成的对象都存放在堆中,对于堆中的对象生命周期的管理由Java虚拟机的垃圾回收机制GC进行回收和统一管理。类的非静态成员变量也放在堆区,其中基本数据类型是直接保存值,而复杂类型是保存指向对象的引用,非静态成员变量在类的实例化时开辟空间并且初始化。
- 方法区:是各个线程共享的内存区域,它用于存储class二进制文件,包含了虚拟机加载的类信息、常量、静态变量、即编译后的代码等数据。它有个名字叫做Non-Heap(非堆),目的是与Java堆区分开。
- JVM栈:JVM栈主要存放在运行期间用到的一些局部变量(基本数据类型的变量)或者是指向其他对象的一些引用,因为方法执行时,被分配的内存就在栈中,所以当然存储的局部变量就在栈中。当一段代码或者一个方法调用完毕后,JVM栈中为这段代码所提供的基本数据类型或者对象的引用立即被释放。
- 本地方法栈:
- 程序计数器:
- 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
- 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
- 参考连接
-
为什么程序计数器、虚拟机栈和本地方法栈是线程私有的?堆和方法区是线程共享的?
- 程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。
- 虚拟机栈和本地方法栈
- 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用到执行完成的过程,对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
- 本地方法栈则为虚拟机使用到的 Native 方法服务。
- 为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。
- 堆和方法区是所有线程共享的资源,堆是进程中最大的一块内存,主要用于存放新创建的对象 (几乎所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即编译器编译后的代码等数据。
- 参考连接
-
常量池、运行时常量池、字符串常量池之间的区别
-
回归Java基础:触发类加载的六大时机
-
JVM运行时数据区域和线程
-
JVM与Java体系结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现