一、JVM 控制的内存区域
主要分为 3 块:
- 线程私有区域(程序计数器、虚拟机栈、本地方法栈)
- 线程共享区域(堆、方法区)
- 直接内存(不是 JVM 运行时数据区域的一部分。如 JDK 中的 nio 使用本地函数库分配堆外内存,使用缓冲区进行这块内存的读写)
3块内存区域的生命周期:
- 线程私有区域,随着用户线程的启动而创建,线程的结束而销毁。
- 线程共享区域,随着虚拟机的启动而创建,虚拟机的停止而销毁。
-
直接内存,通过本地函数库 Unsafe 分配与释放内存。
image.png
二、线程私有区域
1、程序计数器(Program Counter Register)
- 一块较小的内存空间, 是当前线程所执行的字节码的行号指示器
- 每条线程都要有一个独立的程序计数器
- 执行 Java 方法时,程序计数器记录的是字节码指令的地址;执行本地方法时,为空
- 唯一一个没有内存溢出区域
2、虚拟机栈(VM Stack)
- 描述 java 方法执行的内存模型
- 每个方法在执行的同时都会创建一个栈帧(Stack Frame) 用于存储局部变量表、操作数栈、动态链接、方法出口等信息
- 每一个方法从调用直至执行完成的过程,对应着一个栈帧在虚拟机栈中入栈到出栈的过程
- 栈帧是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、方法返回值和异常分派(Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁。方法正常完成、抛出异常未捕获都算作方法结束。
3、本地方法栈(Native Method Stack)
- 虚拟机栈为执行 Java 方法服务;本地方法栈为 Native 方法服务
- 本地方法栈深度溢出或者栈扩展失败时,也会分别抛出 StackOverflowError 和 OutOfMemoryError异常
三、线程共享区域
1、堆(Heap)
- 垃圾收集最重要的内存区域
- 虚拟机规范规定,创建的对象和数组都应当保存在堆内存中
- 一般大小可扩展,通过 -Xms 和 -Xmx 设定最小值和最大值,无法扩展时抛出 OutOfMemoryError 异常
2、方法区(Method Area)
- 存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
- 运行时常量池(Runtime Constant Pool)是方法区的一部分,编译期生成的各种字面量与符号引用也在其中
四、至此可以回答类的静态变量存放在 JVM 运行时的哪块内存了?
HotSpot VM,JDK 6 及之前版本静态变量存放在永久代(Permanent Generation,使用永久代实现的方法区)中;JDK 7 开始,静态变量改存放到 java.lang.Class 对象的末尾,即 Heap 中。虚拟机规范中,是把方法区描述为堆的一个逻辑部分,以上的差异只是实现细节的不同。
静态成员变量存储在堆的永久生成区域中,这是因为static不属于对象而是属于类,所以它被认为是类定义的一部分。如果静态变量是基元类型,它们将存储在permGen中。如果静态变量是一个引用变量,例如static Person obj=new Person()
,那么reference
变量obj
将被存储在permGen中,新创建的objected将被放置在年轻一代中。
©著作权归作者所有:来自51CTO博客作者mb5fdcae3079e89的原创作品,请联系作者获取转载授权,否则将追究法律责任
Java 类的静态变量存放在哪块内存中?
https://blog.51cto.com/u_15061941/2591637
网友评论