赞
踩
同样,根据摩尔定律,我们知道单核
CPU的主频不可能无限制的增长,要想很多的提升新能,需要多个处理器协同工作, Intel总裁的贝瑞特单膝下跪事件标志着多核时代的到来。
基于高速缓存的存储交互很好的解决了处理器与内存之间的矛盾,也引入了新的问题:缓存一致性问题。在多处理器系统中,每个处理器有自己的高速缓存,而他们又共享同一块内存(下文成主存,
main memory 主要内存),当多个处理器运算都涉及到同一块内存区域的时候,就有可能发生缓存不一致的现象。为了解决这一问题,需要各个处理器运行时都遵循一些协议,在运行时需要将这些协议保证数据的一致性。这类协议包括MSI、MESI、MOSI、Synapse、Firely、DragonProtocol等。如下图所示
B站超热门视频:
Java架构师必会六大核心知识点:多线程、JVM、设计模式、MySQL、Redis、ZooKeeperwww.bilibili.com
B站超热门视频:
2020最新马士兵老师讲解多线程与高并发—吊锤P8面试官www.bilibili.com
Java
虚拟机内存模型中定义的访问操作与物理计算机处理的基本一致!
Java
中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存区域main memory,而每个线程又单独的有自己的工作内存,当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而交由线程处理(操作码+操作数)。更多信息我们会在后面的《深入JVM—JVM类执行机制中详细解说》。
在之前,我们也已经提到,JVM的逻辑内存模型如下:
我们现在来逐个的看下每个到底是做什么的!
1、程序计数器
程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看
做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,
各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变
这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、
线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现
的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行
一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要
有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内
存区域为“线程私有”的内存。
如果线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的虚拟机字节
码指令的地址;如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。此
内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。
2、Java 虚拟机栈
与程序计数器一样,Java 虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,
它的生命周期与线程相同。虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执
行的时候都会同时创建一个栈帧(Stack Frame ①)用于存储局部变量表、操作栈、动态
链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在
虚拟机栈中从入栈到出栈的过程。
经常有人把Java 内存区分为堆内存(Heap)和栈内存(Stack),这种分法比较粗
糙,Java 内存区域的划分实际上远比这复杂。这种划分方式的流行只能说明大多数程序
员最关注的、与对象内存分配关系最密切的内存区域是这两块。其中所指的“堆”在后
面会专门讲述,而所指的“栈”就是现在讲的虚拟机栈,或者说是虚拟机栈中的局部变
量表部分。
局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、
float、long、double)、对象引用(reference 类型,它不等同于对象本身,根据不同的虚拟
机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或
者其他与此对象相关的位置)和returnAddress 类型(指向了一条字节码指令的地址)。
其中64 位长度的long 和double 类型的数据会占用2 个局部变量空间(Slot),其余
的数据类型只占用1 个。局部变量表所需的内存空间在编译期间完成分配,当进入一个
方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间
不会改变局部变量表的大小。
在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。