JVM内存区域,开线程影响哪块内存

JVM运行时数据区

 

 

概括地说来:JVM初始运行的时候都会分配好Method Area(方法区)和Heap(堆),而JVM 每遇到一个线程,就为其分配一个Program Counter Register(程序计数器), VM Stack(虚拟机栈)和Native Method Stack (本地方法栈),当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。

 

每当有线程被创建的时候,JVM就需要为其在内存中分配虚拟机栈和本地方法栈来记录调用方法的内容,分配程序计数器记录指令执行的位置,这样的内存消耗就是创建线程的内存代价。

内存作为有限的资源,如果JVM创建了过多的线程,必然会导致资源的耗尽。因此,使用Executor架构复用线程可以节省内存资源,是十分必要的。

JVM的并发是通过线程切换并分配时间片执行来实现的。 在任何一个时刻, 一个处理器内核只会执行一条线程中的指令。因此, 为了线程切换后能恢复到正确的执行位置, JVM需要先保存被挂起线程的上下文环境:将线程执行位置保存到程序计数器中,将调用方法的信息保存在栈中;同时将待执行线程的程序计数器和栈中的信息写入到处理器中,完成线程的上下文切换。维护线程隔离数据区中的内容在处理器中的导入导出,就是线程切换的性能代价。

对象的创建——静态区域加载的多线程安全性

为了保证多线程安全性,一些必要的操作都需要加锁来保证其原子性和可见性,但是类中静态区的代码是不需要加锁就能保证多线程安全性。这是因为什么呢?

答案在于JVM类加载过程的保护机制。和普通类的实例被分配在Java堆上不同,类的静态属性都保存在方法区,其创建收到类加载过程的影响。

类的加载过程大题分为:加载(Loading),连接(Linking),初始化(Initialization),使用(Using)和卸载(UnLoading)五个步骤。

这里和静态属性有关的主要是连接和初始化:

在连接步骤的准备阶段,静态属性会分配内存;在初始化步骤,JVM会生成一个特别的方法——<clinit>方法来专门执行静态代码块和静态变量初始化。

<clinit>方法执行的过程中,JVM会对类加锁,保证在多线程环境下,只有一个线程能成功执行<clinit>方法,其他线程都将被拥塞,并且<clinit>方法只能被执行一次,被拥塞的线程被唤醒之后也不会再去执行<clinit>方法。如果类有继承关系,JVM还会保证父类的<clinit>方法将先于子类的<clinit>方法执行。

由此可见,静态代码块的多线程安全性是由JVM为其加锁实现的,这也是延迟初始化占位类模式的安全性基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值