如何知道写时复制页面是否是实际副本?
当我使用 mmap 创建写时复制映射(MAP_PRIVATE)时,一旦我写入特定地址,该映射的某些页面就会被复制。在我的程序中的某个时刻,我想弄清楚哪些页面实际上已被复制。有一个称为“mincore”的调用,但它仅报告页面是否在内存中,这与是否复制页面不同。
有什么方法可以找出哪些页面已被复制吗?
When I create a copy-on-write mapping (a MAP_PRIVATE) using mmap, then some pages of this mapping will be copied as soon as I write to specific addresses. At a certain point in my program I would like to figure out which pages have actually been copied. There is a call, called 'mincore', but that only reports whether the page is in memory or not, which is not the same as the page being copied or not.
Is there some way to figure out which pages have been copied ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
很好,遵循 MarkR,我尝试过浏览 pagemap 和 kpageflags 界面。下面是一个快速测试,用于检查页面在调用时是否在内存中“交换”。当然还有一个问题,那就是 kpageflags 只能由 root 访问。
测试设置包含 4 页。页 0 和 2 是脏
页 3 已被读取。
第 1 页将不会被访问
页面映射文件将进程的虚拟内存映射到实际页面,然后可以从全局 kpageflags 文件中检索这些页面。 读取文件 /usr/src/linux/Documentation/vm/pagemap.txt
这里我们读取每个虚拟页面的页框编号
现在我们将读取每个虚拟页面的实际页框编号pageflags
总而言之,我对这种方法不是特别满意,因为它需要访问我们通常无法访问的文件,而且非常复杂(一个简单的内核调用来检索 pageflags 怎么样?)。
Good, following the advice of MarkR, I gave it a shot to go through the pagemap and kpageflags interface. Below a quick test to check whether a page is in memory 'SWAPBACKED' as it is called. One problem remains of course, which is the problem that kpageflags is only accessible to the root.
The test setup contains 4 pages. page 0 and 2 are dirty
page 3 has been read from.
page 1 will not be accessed
The pagemap file maps the process its virtual memory to actual pages, which can then be retrieved from the global kpageflags file later on. Read the file /usr/src/linux/Documentation/vm/pagemap.txt
Here we read the page frame numbers for each of our virtual pages
Now we are about to read for each virtual frame, the actual pageflags
All in all, I'm not particularly happy with this approach since it requires access to a file that we in general can't access and it is bloody complicated (how about a simple kernel call to retrieve the pageflags ?).
我通常使用 mprotect 将跟踪的写时复制页面设置为只读,然后通过将给定页面标记为脏并启用写入来处理生成的 SIGSEGV。
它并不理想,但开销是相当可管理的,并且可以与 mincore 等结合使用来进行更复杂的优化,例如管理工作集大小或近似页面的指针信息您希望进行换出,这可以让运行时系统与内核合作而不是与之对抗。
I usually use
mprotect
to set my tracked copy-on-write pages to read-only, then handle the resulting SIGSEGVs by marking the given page dirty and enabling writing.It isn't ideal, but the overhead is quite manageable and it can be used in combination with
mincore
, etc. to do more complicated optimizations, like manage your working set size or to approximate pointer information for pages you expect to have swap out, which lets the runtime system cooperate with the kernel rather than fight it.确定这一点并不容易,但却是可能的。为了查明一个页面是否是另一个页面(可能是另一个进程的)的副本,那么您需要执行以下操作(最近的内核):
然后您可以确定内存中的两个页面实际上是同一页面。
做到这一点相当棘手,你需要成为 root,无论你做什么,都可能会出现一些竞争条件,但这是可能的。
It is not easy, but possible to determine this. In order to find out whether a page is a copy of another page (possibly another process's) then you need to do the following (recentish kernels):
You can then determine that two pages are actually the same page, in memory.
It is fairly tricky to do this, you need to be root, and whatever you do will probably have some race conditions in it, but it is possible.
写时复制是使用虚拟内存硬件的内存保护方案来实现的。
当写入只读页时,会发生页错误。页错误处理程序检查该页是否带有写时复制标志:如果是,则分配新页,复制旧页的内容,然后重试写入。
新页面既不是只读的也不是写时复制,到原始页面的链接完全断开。
因此,您需要做的就是测试页面的内存保护标志。
在 Windows 上,API 为
GetWorkingSet
,请参阅 中的说明VirtualQueryEx
。我不知道对应的linux API是什么。Copy-on-write is implemented using the memory protection scheme of the virtual memory hardware.
When a read-only page is written to, a page fault occurs. The page fault handler checks if the page carries the copy-on-write flag: if so, a new page is allocated, the contents of the old page and copied, and the write is retried.
The new page is neither read-only nor copy-on-write, the link to the original page is completely broken.
So all you need to do is test the memory protection flags for the page.
On Windows, the API is
GetWorkingSet
, see the explanation atVirtualQueryEx
. I don't know what the corresponding linux API is.我给了一个类似的人的答案 目标并引用了与您类似的问题。
我认为 bmargulies 的 当这两个想法结合起来时,这个问题的答案完全符合您的需要。
I gave an answer to someone with a similar goal and referenced a question similar to yours.
I think bmargulies' answer to that question fits what you need perfectly when the two ideas are combined.
我不记得有这样的 API 被导出。你为什么要做这样的事情(你正在解决的问题的根源是什么?)
你可能想看看 /proc/[pid]/smaps (它提供了所使用页面的详细统计信息/复制/存储)。
再说一次,你为什么要这么做?如果您确定这种方法是唯一的方法(通常,使用了虚拟内存并忘记了),您可能需要考虑编写一个处理此类功能的内核模块。
I don't recall such API being exported. Why do you want to do such a thing (What is the root of the problem you're solving?)
You might want to take a look at /proc/[pid]/smaps (which provides a somewhat detailed statistic of pages used/copied/stored).
Again, why would you want to do that? If you're sure this approach is the only one (usually, virtual memory is used and forgot about), you might want to consider writing a kernel module that handles such functionality.