清除Mac OS X上的缓存缓冲区

15

有没有一种方法在 Mac 上以编程方式清除缓冲区高速缓存,最好使用 C 语言?

基本上,我正在寻找相当于10.5(及更高版本)中 purge 命令的源代码等价物。编辑:我现在看到这是 CHUD 工具的一部分,但似乎源代码不直接可用。然而,我仍在寻找一些能够实现相同功能的代码。


1
你的真正目标是什么?是确保你写入文件的数据真正存储到磁盘上吗?如果是,那么请考虑在open()调用中使用符合POSIX标准的O_DSYNC或O_SYNC选项。 - Jonathan Leffler
哇,那是五年前的事了,但是你还能帮我实现同样的目标吗?接受的答案看起来很棒,但我不懂汇编语言,所以对我来说有点无用:( - Coldsteel48
5个回答

12

我已经反汇编了问题中的函数(_utilPurgeDiskBuffers)从CHUD框架中。该函数似乎并不是非常复杂,但由于我不是MacOS程序员,所以导入和调用的系统API对我来说没有太多意义。

该API要做的第一件事是调用另一个函数,即_miscUtilsUserClientConnect_internal。该函数似乎建立了与CHUD内核扩展的连接。
为此,它调用_getCHUDUtilsKextService,该函数尝试使用从I/O kit导入的IORegistryCreateIterator枚举所有kexts以定位CHUD内核扩展。找到kext后,通过_IOServiceOpen打开它。

这时,我们就有了与CHUD kext的连接(至少在我的反编译列表中是这样的)。

最后,调用IOConnectMethodStructureIStructureO,我想这里进行了真正的奇迹。
不知道一些内部细节或函数签名,参数对我来说毫无意义。

以下是反汇编的代码:

__text:4B0157A7 lea     eax, [ebp+var_1C]
__text:4B0157AA mov     dword ptr [esp+14h], 0
__text:4B0157B2 mov     [esp+10h], eax
__text:4B0157B6 mov     [esp+0Ch], eax
__text:4B0157BA mov     dword ptr [esp+8], 0
__text:4B0157C2 mov     dword ptr [esp+4], 0Eh
__text:4B0157CA mov     [esp], edx
__text:4B0157CD call    _IOConnectMethodStructureIStr

请注意,var_1C在此之前已被清零。

希望你们中的一些人能够更好地理解那些系统调用。如果需要更多信息,请告诉我。

更新:
为了让您开始,只需从IO kit SDK中获取AppleSamplePCIClient.c示例。这基本上就是CHUD工具中的Purge应用程序所做的事情。
唯一需要更改的是最终_IOConnectMethodStructureIStr调用的参数。从上面的反汇编列表中获取它们即可。由于我没有Mac,无法测试所有这些东西。


我想做这个,但我不懂汇编语言,你能帮我弄清楚参数吗? - Coldsteel48

6

看起来:

你可以使用usr/bin/purge(在终端中键入purge)来清除磁盘缓存(非活动内存),或者你可以从硬盘读取许多随机数据以达到同样的效果

引自用户guns评论


4

如果您只是想针对某个文件关闭缓存,那么这也许是一种替代方案。具体取决于你的目标是什么。这里有一个很好的总结

UBC can be cleared by running 'purge' which allocates a lot of memory to force the cache to clear.

fcntl(fd, F_GLOBAL_NOCACHE, 1)  

can be used turn caching off for a particular file. This can be done in any process and the file can be closed after.


1
我只是提供这个作为另一种选择,因为不知道你具体在做什么。如果不适合你的情况,请忽略它。有时候,当你需要经常清除缓存时,可能是因为本来就不应该缓存它。 - lpfavreau
3
我认为,即使像这样关闭缓存(使用F_NOCACHE或F_GLOBAL_NOCACHE),如果文件的某些页面已经在页面缓存中,它们仍然会被使用。我尝试使用direct=1选项来使用fio(1)进行测试。结果似乎证实了我的怀疑(在我的MBP上使用一个磁盘硬盘而不是SSD,进行随机读取时,我获得了约1200MB/s的吞吐量)。我已经通过dtruss确认fio(1)确实正确地调用了fcntl。 - Aktau
2
在运行“sudo purge”并尝试相同的fio(1)调用后,速度慢了许多。因此,是的,在Linux上,似乎F_NOCACHE没有直接等价于O_DIRECT - Aktau

3

你可以多次使用 sync(2)(就像众所周知的习语 sync; sync; sync)。 我似乎找不到 purge 的源代码,但它可能只是可在 10.5.6 代码中 获得的 man 包的一部分。


Purge是CHUD的一部分,所以你找不到源代码;-) - Jason Coco
那么,这是意味着源代码不可用,还是只是隐藏了? - Sophie Alpert
1
Keltia,那只会强制写入磁盘,它并没有真正清除缓存。 - Sophie Alpert
除了尝试对其进行反汇编或在 DTrace 下运行它之外,我没有看到其他方法,除非获得访问源代码的权限。 - Keltia

2
当你没有想要模拟的工具的源代码时(就像这里的情况一样),有许多方法可以解决。
1/ 从你的C代码中,使用system()函数调用该工具。只要没有可见的影响(比如打开一个图形窗口),这种方法就很有效。例如,你可以使用system("/path/to/purge -purgargs >/dev/null 2>&1");
2/ 反向工程代码以查看它是如何实现的。这有点棘手,因为它需要对汇编语言、系统调用和许多其他内容有所了解。
3/ 联系开发人员以获取关于它是如何完成的提示。这不必是一个“把代码发送给我,这样我就可以抄袭并赚钱”的问题。你可以表达为“我有兴趣使用purge进行开发,但我不确定它到底是做什么的”或者“我在运行代码时有安全问题,权力机构不会让我运行它,除非我们确切地知道它做了什么”。然后你就可以编写自己的代码来完成相同的事情。
如果可能的话,我会选择选项1(我天生懒惰:-)。如果你要编写一个与purge竞争的工具(这将很困难,因为它是免费的),选项2可能是最好的选择。

我猜如果我去请求他们一些专有源代码,苹果公司可能不会那么乐意提供帮助。 - Sophie Alpert
不,我认为他们也不会这样做,这就是为什么我建议你用更加隐晦的方式来表达 :) 无论如何,你并不需要他们的代码(使用它可能会导致你的代码成为衍生作品/版权侵犯)。你只需要知道概念上如何实现它。 - paxdiablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接