当前位置:  开发笔记 > 编程语言 > 正文

内存分配功能是否表示不再使用内存内容?

如何解决《内存分配功能是否表示不再使用内存内容?》经验,为你挑选了1个好方法。

当处理某些数据流(例如,来自网络的请求)时,使用一些临时存储器是很常见的.例如,URL可以分成多个字符串,每个字符串可能从堆中分配内存.这些实体的使用通常是短暂的,并且内存总量通常相对较小,应该适合CPU缓存.

在用于临时字符串的内存被释放时,字符串内容很可能只存在于缓存中.但是,CPU并不知道要释放的内存:释放只是内存管理系统中的更新.结果,当CPU高速缓存用于其他存储器时,CPU可能最终不必要地将未使用的内容写入实际存储器 - 除非存储器释放以某种方式向CPU指示存储器不再被使用.因此,问题变为:

释放内存的内存管理功能是否表示可以丢弃相应内存的内容?有没有办法向CPU指示不再使用内存?(至少,对于某些CPU:显然,架构之间可能存在差异)由于不同的实现可能会在质量上有所不同,可能会或可能不会做任何花哨的事情,问题实际上是否有任何内存管理实现将内存指示为未使用?

我确实意识到始终使用相同的内存领域可能是一种缓解策略,以避免对实际内存的不必要写入.在这种情况下,将使用相同的缓存内存.类似地,内存分配可能总是产生相同的内存,也避免了不必要的内存传输.但是,我可能不需要依赖任何适用的技术.



1> Iwillnotexis..:

没有.

您提到的缓存操作(将缓存内存标记为未使用并丢弃而不回写到主内存)称为缓存线无效而不进行回写.这是通过带有操作数的特殊指令来执行的,该操作数可以(或可以不)指示要使无效的高速缓存行的地址.

在我熟悉的所有架构中,这条指令很有特权,我认为这是有充分理由的.这意味着用户模式代码不能使用该指令; 只有内核才可以.否则,可能存在的变态技巧,数据丢失和拒绝服务的数量是令人难以置信的.

因此,没有内存分配器可以做你的建议; 他们根本没有(在用户模式下)这样做的工具.

建筑支持

86X86-64架构具有特权invd指令,这会使所有内部缓存不写回,并指示外部缓存也无效自己.这是唯一能够在没有回写的情况下无效的指令,它确实是一种钝器.

非特权clflush指令指定受害者地址,但它在无效之前写回,所以我只是顺便提一下.

所有这些说明的文档都在英特尔的SDM第2卷中.

所述ARM架构执行高速缓存无效而不与回写的写入到协处理器15中,寄存器7:MCR p15, 0, , c7, , .可以指定受害者缓存行.写入此寄存器是特权.

PowerPC具有dcbi,它允许您指定受害者,dci但不指定受害者和两者的指令高速缓存版本,但所有四者都具有特权(参见第1400页).

MIPS具有CACHE可以指定受害者的指令.它在MIPS指令集v5.04中享有特权,但在6.04中,Imagination Technologies混淆了水,而且不再清楚什么是特权,什么不是.

因此,这不包括使用缓存失效而不在用户模式中直接刷新/写回.

内核模式?

但是,我认为在kernelmode中它仍然是个坏主意,原因有很多:

Linux的分配器,kmalloc()为不同大小的分配分配竞争对手.特别是,它具有每个分配大小<=192字节的竞技场,步长为8; 这意味着对象可能比高速缓存行更接近彼此,或者与下一个对象部分重叠,因此使用失效可能会破坏正确位于高速缓存中但尚未写回的附近对象.这是错的.

高速缓存行可能非常大(在x86-64,64字节上),而且整个高速缓存层次结构中的大小不一定均匀,这一问题更加复杂.例如,Pentium 4有64B L1高速缓存行,但有128B L2高速缓存行.

它使释放时间与要解除分配的对象的高速缓存行数成线性关系.

它的好处非常有限; L1缓存的大小通常在KB中,因此几千次刷新将完全清空它.此外缓存可能已经刷新数据没有你的提示,让您的失效是有害无益:内存带宽使用,但你不再有高速缓存行,所以当它接下来将部分写入的需要被重新获得.

下一次内存分配器返回该块时(可能很快),其用户将遭受保证的高速缓存未命中并从主RAM获取,而他可能有一个脏的未刷新线或干净的刷新线.保证高速缓存未命中和从主RAM获取的成本比高速缓存行刷新大得多,而无需通过高速缓存硬件自动和智能地隐藏在某处.

循环和刷新这些行所需的附加代码浪费了指令缓存空间.

更好地利用前面提到的循环使缓存行无效的几十个周期将继续做有用的工作,同时让缓存和内存子系统的相当大的带宽写回你的脏缓存行.

我现代的Haswell处理器具有32字节/时钟周期写入L1带宽和25GB/s主RAM带宽.我确信在那里的某个地方可以挤出一些额外可刷新的32字节高速缓存行.

最后,对于像这样的短期小分配,可以选择在堆栈上分配它.

实际的内存分配器实践

着名的dlmalloc不会使释放的内存无效.

glibc 不会使释放的内存无效.

jemalloc 不会使释放的内存无效.

musl-libc malloc()不会使释放的内存无效.

它们都没有使内存无效,因为它们不能.为了使高速缓存行无效而进行系统调用将非常缓慢,并且会因为上下文切换而导致更多的流量进出缓存.

推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有