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

标签 performance memory memory-management dynamic-memory-allocation cpu-cache

在处理某些数据流(例如来自网络的请求)时,通常使用一些临时内存。例如,一个URL可以拆分为多个字符串,每个字符串都可能从堆中分配内存。这些实体的使用通常是短暂的,总内存量通常相对较小,应该适合于CPU缓存。
此时,用于临时字符串的内存被释放,字符串内容很可能只存在于缓存中。但是,CPU不知道正在释放的内存:释放只是内存管理系统中的一个更新。因此,当CPU缓存用于其他内存时,CPU可能会不必要地将未使用的内容写入实际内存,除非内存释放以某种方式向CPU指示内存不再使用。因此,问题变成:
内存管理功能释放内存是否表示可以丢弃相应内存的内容?是否有一种方法可以向CPU指示内存不再使用?(至少,对于某些CPU:显然,架构之间可能存在差异)由于不同的实现在质量上可能会有所不同,可能会或可能不会做任何花哨的事情,问题是是否有内存管理实现指示内存未使用?
我确实认识到,始终使用相同的内存领域可能是一种缓解策略,以避免对实际内存进行不必要的写入。在这种情况下,将使用相同的缓存内存。同样,内存分配可能总是产生相同的内存,同时避免不必要的内存传输。然而,我可能不需要依赖于这些技术中的任何一种。

最佳答案

不。
您提到的缓存操作(将缓存内存标记为未使用并丢弃而不写回主内存)称为不写回的缓存线无效化。这是通过一条特殊指令来执行的,该指令的操作数可能(也可能不会)指示要失效的缓存线的地址。
在我熟悉的所有体系结构中,这个指令是特权的,我认为这是有充分理由的。这意味着用户模式代码不能使用该指令;只有内核可以。如果不是这样的话,可能出现的欺诈、数据丢失和拒绝服务的数量是难以置信的。
因此,没有内存分配器可以做您建议的事情;它们只是没有(在用户模式下)这样做的工具。
建筑支撑
x86和x86-64体系结构具有特权invd指令,该指令使所有内部缓存失效,而不进行写回,并指示外部缓存也使其失效。这是唯一一个没有写回就可以失效的指令,而且它确实是一个钝器。
非特权clflush指令指定了一个受害者地址,但它在失效之前会写回,所以我只是在传递中提到它。
所有这些指令的文档都在Intel的第2卷中。
ARM体系结构使用SDMsMCR p15, 0, <Rd>, c7, <CRm>, <Opcode_2>执行缓存无效而不进行写回。可以指定受害者缓存线。写入此寄存器是特权的。
PowerPC具有dcbi,允许您指定受害者,dci不指定受害者,CACHE和指令缓存版本,但这四个版本都是特权的。
MIPS具有可以指定受害者的a write to coprocessor 15, register 7指令。它享有特权,但在6.04年的想象技术中,水被搅浑了,不清楚什么是特权,什么不是。
因此,这排除了在用户模式下不直接刷新/写回缓存无效的使用。
内核模式?
但是,我认为在KernelMode中,这仍然是一个坏主意,原因有很多:
Linux的分配器为不同大小的分配从arenas中进行分配。特别是,它对于每个分配大小的字节都有一个竞技场,其步骤为kmalloc();这意味着对象可能比缓存线更接近彼此,或者部分地重叠下一个缓存线,因此使用invalidation可以吹出缓存中正确但尚未在缓存中的附近对象。里顿回来了。这是错误的。
缓存线可能非常大(在x86-64、64字节上),而且在整个缓存层次结构中大小不一定一致,这一事实使这个问题更加复杂。例如,奔腾4有64B的一级缓存线,而128B的二级缓存线。
它使要解除分配的对象的缓存线数中的解除分配时间呈线性。
它的好处非常有限;一级缓存的大小通常在KB中,因此几千次刷新将完全清空它。此外,缓存可能已经在没有提示的情况下刷新了数据,因此您的无效性比无用性更糟糕:使用了内存带宽,但您不再拥有缓存中的行,因此当它下次部分写入时,需要重新蚀刻。
下次内存分配器返回该块(可能很快就会返回)时,该块的用户将遭受保证的缓存丢失和从主RAM中提取,而他可能会有一个脏的未刷新行或一个干净的刷新行。保证从主RAM中缓存丢失和获取的成本远大于缓存线刷新,而缓存硬件不会自动智能地将无效数据塞进某个地方。
循环和刷新这些行所需的附加代码浪费了指令缓存空间。
对于上述循环所花费的几十个循环,使缓存线失效的一个更好的用途是继续做有用的工作,同时让缓存和内存子系统的大量带宽写回脏的缓存线。
我的现代哈斯韦尔处理器有32字节/时钟周期写一级带宽和25GB/s主RAM带宽。我确信可以在其中的某个地方压缩几个额外的可清洗的32字节缓存线。
最后,对于这种短期的、小的分配,可以选择在堆栈上分配它。
实际内存分配器实践
famed(see page 1400)不会使释放的内存失效。
<=192不会使释放的内存无效。
8不会使释放的内存无效。
glibc-libc'sjemalloc不会使释放的内存无效。
它们都不能使内存无效,因为它们不能。为了使缓存线无效而进行系统调用既会非常慢,也会导致更多的缓存进出流量,这仅仅是因为上下文切换。

关于performance - 内存分配功能是否表示不再使用内存内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34038241/

相关文章:

c++ - 如何在不使用太多内存的情况下链接大量 C++ 目标文件?

c - 如何在不使用 realloc() 的情况下扩展字符串容量?

javascript - 检查多个值并显示错误

Java: getInstance() 单例性能

ios - 弹出一个具有异步任务的 viewController,它会在 iOS 任务完成之前销毁吗?

python - 如何强制 Python 字典缩小?

c++ - 试图从内存中删除字符串。不会让我分配给 cin

c++ - 如何加速这个 Rcpp 函数?

python - 如何加快 Tensorflow 2 keras 模型的推理速度?

c - 从进程内部查找映射的内存