JVM内存模型

JVM内存模型

JVM逻辑分区主要分为5个主要的模块
线程私有:本地方法栈,程序计数器,虚拟机栈
线程共享:堆,方法区

程序计数器:
很小的一部分空间,给每一个线程单独分配的行指示器,唯一一个不会OOM的内存空间
由于多个cpu与主存交互时会有多个cpu私有的高速cache,因为只有一个主存,所以需要一个内存屏障(读写锁)来管理这些高速缓存,那么写的时候有可能会有线程切换的情况,这时候程序计数器就能记录切换之前的执行状态,以便线程继续执行

Java栈(虚拟机栈):
这就是平常所说的栈,描述的是方法的生命周期,每执行一个方法就会创建一个栈帧用于存储局部变量表(八大基本类型和对象的引用),操作栈,动态链接,方法出口等信息
由于栈帧在编译期间就会固定大小,所以如果是虚拟机栈动态扩容内存不够就会OOM,或者是线程编译新增栈帧入虚拟机栈栈满溢出会报StackOverflowError
栈帧的旅程:
内存 -> 运行时数据区 -> 某个线程对应的虚拟机栈 -> here[在这里]

本地方法栈:
跟Java栈相似,不同的是在本地方法栈中存的是native方法(底层与C语言交互的接口方法)

堆:
主要存储对象的实例和数组,GC主要的场所
逃逸分析:通过逃逸分析来决定某些实例或者变量是否要在堆中进行分配,如果开启了逃逸分析,即可将这些变量直接在栈上进行分配,而非堆上进行分配。这些变量的指针可以被全局所引用,或者其其它线程所引用
根据虚拟机规范,Java堆可以存在物理上不连续的内存空间,就像磁盘空间只要逻辑是连续的即可

方法区(非堆):
和堆一样是线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量,如static修饰的变量加载类的时候就被加载到方法区中
jdk1.7以前方法区也叫永久代,运行时常量池是方法区的一部分,class文件除了有类的字段、接口、方法等描述信息之外,还有常量池用于存放编译期间生成的各种字面量和符号引用。
JDK1.8后就废除了永久代概念,转而使用元空间

public class StringIntern {
    //运行如下代码探究运行时常量池的位置
    public static void main(String[] args) throws Throwable {
        //用list保持着引用 防止full gc回收常量池
        List<String> list = new ArrayList<String>();
        int i = 0;
        while(true){
            list.add(String.valueOf(i++).intern());
        }
    }
}
//如果在jdk1.6环境下运行 同时限制方法区大小 将报OOM后面跟着PermGen space说明方法区OOM,即常量池在永久代
//如果是jdk1.7或1.8环境下运行 同时限制堆的大小  将报heap space 即常量池在堆中

JIT编译产物:
即时编译热点代码的字节码

对象访问有两种方法,一种是句柄访问,一种是直接访问
(对象实例数据:对象的实例字段数据(堆)/对象类型数据:对象类型的信息数据(方法区))

句柄访问:
优点:JAVA堆GC的时候只用改变对象示例数据的指针指向,不影响ref指针的指向
缺点:相比较直接访问要慢,访问一个对象多了一次指针定位
在这里插入图片描述
直接访问:
优点:速度快
缺点:堆GC时,ref指针需要重新指向新的地址
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值