全貌
盗图一张如下:
程序计数器
- 记录字节码文件当前的执行行数
- 是每个线程私有的,共有的话,切换线程会懵逼掉的
- 如果执行native方法的话,它的值是undifined。因为native方法是java通过JNI直接调用本地C/C++库,可以近似的认为native方法相当于C/C++暴露给java的一个接口,java通过调用这个接口从而调用到C/C++方法。由于该方法是通过C/C++而不是java进行实现。那么自然无法产生相应的字节码,并且C/C++执行时的内存分配是由自己语言决定的,而不是由JVM决定的。
- 不会oom。因为它的空间很小并且不是我们申请的,是jvm自己管理的。
虚拟机栈
- 它是跟方法对应的,是用来描述方法调用过程中的内存模型。(方法区是跟class对应的)
- 栈帧:他的数据结构是个栈,每个方法对应一个栈帧,假如执行a方法,a方法中又调用了b方法,那么会先把a 压栈,执行到b的时候把b压栈,b执行完b出栈,之后接着执行a,a执行完a出栈。
- 局部方法表:每个方法执行需要的内存大小在编译的时候就确定了,局部方法表存放执行方法需要的变量,如果该变量是个对象的话,存放的是引用。局部方法表是在栈帧中的。(所有对象的真实存放区域是堆)
- 虚拟机的栈的深度是有最大值的,如果栈太深会报stackoverflow
- 如果方法执行没有到达栈的最大值,但是没有内存空间可用了,那么会报oom
- 线程私有的
本地方法栈
- 虚拟机栈跟本地方法栈基本一致,只不过不是java方法,而是对应native方法
- 线程私有的
- 会有oom跟stackoverflow
堆
- 存放对象的
- 线程共享的
- gc主要的目标
- 会oom
方法区
- 存放类信息(跟class对应),存放常量(常量池,1.8 将常量池放入了堆),存放静态变量等
- 线程共享的
- 会oom
- 在java8中被移除了,取而代之的是metaspace(元数据空间)
eg:
运行如下代码:以下只分析1.8
1 | String a = "123"; |