b JMM java 内存模型
文章目录
一、JMM内存模型
运行过程描述
该过程会串联启内存模型的各个功能便于理解JVM的行为,和JMM的作用
-
java文件被编译成class文件。
class包含常量信息
,栈信息方法
,和字节码指令
,类的继承和依赖关系信息
。 -
jvm启动时,根据启动参数申请
内存
创建JVM实例,包括方法区
,堆
,虚机栈
,本地方法栈
,程序计数器
。 -
创建
bootstarp
类加载器,逐次加载系统类和用户类。这些class
信息被放在方法区
,方法区
同时还放类信息、常量、静态变量
。 -
jvm是懒加载机制,
new
类时会先在方法区
中寻找,找不到时会加载
,不用时GC
会卸载。启动时bootstarp.classloader
会加载luncher
类,加载main
方法,这也算是主线程。 -
注意
虚拟机栈
、本地方法栈
、和程序计数器
,是线程独有的,随着主线程创建会产生。如果运行时有新的线程
,也会创建新的。 -
程序运行时
new
实例时,对象实例会放在Heap
堆中,这时jvm直接管理的一块内存会存储实例
和数组
,注意Sting
也算数组,放在堆
上。 -
虚拟机栈
包含局部变量栈
,操作数栈
,动态链接
,返回地址
,当前栈帧信息
。执行方法时,会根据class
定义的信息,把局部变量、操作数压入相应栈。运行时才确定的引用,叫动态链接,也放入栈。 -
如果指令调用到了
本地方法
,就会把局部变量,等信息放入本地方法栈
。 -
程序计数器
是线程级别的,保留着,当前进程的的当前操作数(指令)
。这也是多线程不干扰的原因。 -
GC会不定时的,对堆进行压缩,对不用的
class
进行删除。因此class
的卸载也是不可控的。
二、详细介绍
2.1 程序计数器
- 线程私有,无OOM错误
保持对虚拟机栈
中操作数栈
的引用,持有当前操作数
,指示JVM该去执行的行为。
2.2 虚拟机栈
- 线程私有
- 每个元素叫栈帧。
线程在调用Java方法时,会为每一个方法创建一个栈帧,来存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法被调用和完成的过程,都对应一个栈帧从虚拟机上入栈和出栈的过程。
- 示意图
2.3 本地方法栈
- 线程私有,和虚拟栈类似。
为线程私有,功能和虚拟机栈非常类似。来存储线程调用本地方法时,本地方法的局部变量表、操作栈等信息。
2.4 堆
- JVM创建,所有线程共享。
- 存储
实例
,数组
,String
。 - 可以被细分
老年代
,年轻代
等(不同GC分法不同),是GC回收的主要地点。
2.5 方法区
- JVM创建,所有线程共享。
- 存储
class信息
,常量
,静态变量
,即时编译的代码信息。
三、直接内存和HEAP
- 不属于jvm管理,需要手动清楚
- 受限于
主机内存
它起源于NIO
包,网络连接时读和写的缓存区域
。
四、常见错误
OOM 内存溢出
OutOfMemoryError
,指的是内存不够了,已有的内存不满足于申请的内存。
内存泄露
memory leak,是指存在异常的引用,使得空间无法被回收。直到内存溢出。两个不冲突。