java内存结构_编程基础:Java内存模型难理解,看看计算机内存结构就明白了

34a19cd4368026a32d4c20353499430e.png

深挖底层

前面层级发文说过计算机内存体系的相关概念,本文继续详细说一下有关计算机内部存储体系的组织结构和每一个的相关细节。

我们都了解了,计算机的内部存储有暂时寄存型的,比如集成在CPU里的各类寄存器,还有高速缓存寄存器,它们位于CPU和我们的主内存之间,当然这种高速缓存器还分了一级和二级等,然后就是我们的主内存存储器以及次级内存存储,到外部的硬盘和磁带之类的永久性存储设备。

无疑这其中跟我们编程关系最密切的就是高速缓存和主内存,所以我们在详细说一下它们具体的细节内容。

CPU的各类寄存器就不说了,因为它们集成在CPU单元里,所以容量有限,特点是能够支持CPU运算,速度极快,但是好东西都贵,所以不可能把它们的容量搞的很大。如此为了进一步发挥CPU的性能效率,只能在寄存器和主内存之间在添加一类缓冲容器,这就是高速缓冲存储器。

高速缓冲存储器是一种特殊的高速存储器,它用来加速主内存内容与高速的CPU同步的。它比主存或磁盘内存更贵,但比CPU寄存器便宜。是一种非常快的内存类型,它充当RAM和CPU之间的缓冲区。

它可以用来保存CPU频繁请求的数据和指令,以便在需要时立即提供给CPU,而不用去访问RAM。

b2ee101020804c1e18b63928c620d67b.png

这种高速缓存内存用于减少从主内存访问数据的平均时间。缓存是一种更小、更快的内存,它存储来自经常使用的主内存位置的数据副本。CPU中有多种不同的独立缓存,用于存储指令和数据。

计算机内补存储层级

  • L1(各类寄存器):它是一种存储和接受数据的内存类型,数据立即存储在CPU中。最常用的寄存器有累加器、程序计数器、地址寄存器等。
  • L2(高速缓存存储器):它是速度最快的内存,具有更快的访问时间,数据被临时存储以便更快地访问。
  • L3(主内存存储器):计算机当前工作的内存很小,一旦断电,数据就不再留在内存中
  • L4(次级存储器):它是外部存储器,它不像主存储器那样快,但是数据永久地留在这个存储器中。

高速缓存的性能测量方面

当处理器需要对主内存中的某个位置进行读取或写入时,它首先检查缓存中的对应条目。如果处理器发现内存位置在缓存中,也就是命中缓存,因此会直接从缓存中读取数据。

如果处理器没有在缓存中找到内存位置,就会发生缓存丢失。对于缓存丢失,缓存分配一个新条目并从主内存中复制数据,然后从缓存的内容中完成请求。高速缓存的性能通常是通过一个称为命中率的量来度量的。

我们可以使用更大的缓存块、更高的关联性、更高的命中率、减少脱靶率,更小的错过惩罚以及更短的命中缓存的时间来提高缓存性能。

c94fd291d896b96f90d918644b26cb06.png

缓存映射

由于越靠近CPU的缓存性能越好,但是空间也越小,如果想将外层更多的数据装入到内层缓存,就需要采用映射机制了。目前对于高速缓存与主内存之间的映射机制主要有三种分别是:

直接映射关联映射集合关联映射

直接映射技术最简单,就是直接将主内存每个块映射到一个可能的高速缓存行上。 或在直接映射中,将每个内存块分配给缓存中的特定行。如果在需要加载新块时,如果该行被先前的内存占用了,则先前的块会被丢弃。

其地址空间分为索引字段和标记字段两部分。缓存用来存储其标记字段,而其余存储在主内存中。

直接映射的性能与命中率成正比。可用如下公式表示:

 i = j mod m

这里,i 是缓存行数, j 是主内存块数,m 是缓存中的行数

对于高速缓存访问,可以将每个主内存地址看作由三个字段组成。最不重要的w位标识主内存块中唯一的字或字节。在大多数现代计算机中,地址都是字节级的。其余的s位指定主存的2的s次方块之一。缓存逻辑将这些s位解释为s-r位(最重要的部分)的标记和r位的行字段。后一个字段标识缓存的m=2的r次方行之一。

关联映射

在这种类型的映射中,关联内存用于存储内容并同时处理内存单词。任何块都可以进入缓存的任何行。这意味着字 id位用于标识块中需要的字,但是标记成为所有剩余的位。

这允许在高速缓存内存中的任何位置放置任何字。它被认为是最快和最灵活的映射形式。

集合关联映射

集合关联映射是一种增强的直接映射形式,消除了直接映射的缺点。

集合关联解决了直接映射方法中可能出现的抖动问题。

不是只有一行数据块可以映射到缓存中,我们将把几行放在一起创建一个set集合。然后,主内存中的块可以映射到指定集合的任何行里。

集合关联映射允许缓存中出现的每个单词在主内存中可以有两个或多个单词,用于相同的索引地址。

集合关联缓存映射结合了最佳的直接映射和关联缓存映射技术。

在这情况下,由输个集合构成的缓存,每个都是有一定数量的行构成。

m = v * ki= j mod v

这里,i 是缓存集合数,j 是主内存块数,v 是集合数,m 是缓存集中的行数 ,k 是每个集合中的行数。

fce3ec97bc2d99939fa63ea560bdce9b.png

高速缓存应用

通常,高速缓存内存可以在任何给定的时间内存储合理数量的主内存块,但是与主内存中的块总数相比,这个数量还是很小的。

主内存块与缓存中内存块之间的对应关系由映射函数指定。

高速缓存类型:

  • 主高速缓存:主缓存总是位于处理器芯片上。这个缓存很小,它的访问时间与处理器寄存器的访问时间相当。
  • 次级高速缓存:次级高速缓存位于主高速缓存和其余内存之间,它被称为二级(L2)缓存。通常,二级缓存也驻留在处理器芯片上。

因为高速缓存的大小比主内存小。因此,要检查主存的哪一部分应该被赋予优先级并加载到高速缓存中,需要根据引用的位置来决定。

引用局域性类型

  • 引用空间局域性:也就是说元素有机会出现在引用点非常接近的地方,下次在查找时更靠近引用点。
  • 引用时间局域性:在这里最近最少使用算法将被使用,无论何时每当分页错误发生在一个word里,将不仅在主内存加载word,而且还会加载完整的页面错误。

因为引用空间局域性规则说,如果你引用任何字紧邻我们寄存器中被引用的字,这就是为什么我们加载完整页表,这样完整块就会被加载。

d0f2cb27bf3f8cb47995d48aae97e70a.png

内存模型设计之道

概括一下

对于引用局域性我们可以简单理解成:在时间和空间上都要尽量的将彼此相连的内容尽量放到一起。

空间和时间局部性描述了程序访问数据(或指令)的两种不同特性。

如果在时间上被引用的对象在空间上也很接近(如附近的内存地址、磁盘上的邻近扇区等),则一系列引用具有空间局域性。

如果对同一事物的访问在时间上聚集在一起,则序列具有时间局域性。

如果一个程序访问在一个大数组,每个元素读取一次,然后移动到下一个元素,不重复访问任何给定的位置,直到它触及其他位置那么明确的空间位置而不是时间局部性。

另一方面,如果一个程序在进入另一个随机子集之前,花费时间反复访问数组中位置的随机子集,那么它将具有时间局域性,而不是空间局域性。

一个编写良好的程序将具有的数据结构将一起访问的东西组合在一起,从而确保空间的局域性。

如果程序很可能在访问A之后不久访问B,那么A和B应该在彼此附近分配。

总结:

这里所说的这些内部存储架构以及缓存之间的映射关系,都是我们Java编程中必须要面对的编译优化和执行优化的理论基础,理解了这些缓存的差异以及缓存之间如何引用,装入排出,我们就知道在java性能优化时,编译器要做的重排,以及对象可见性的规定,其实都是在为统一高速缓存内容和主内存内容的一致性而做的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值