Linux上的munmap性能

3
我在RHEL 5.8上开发了一个多线程应用程序,通过mmap读取大文件(每个文件约500MB),并进行一些处理。其中一个线程执行mmap操作,其他线程执行处理操作。当文件不再存在于文件系统中时,执行munmap以释放内存。
我的问题是munmap(有时还包括对文件的关闭)会减缓其他线程,这些线程在处理不同的内存块,因此我想知道是否有更好的实现方式。我有两个想法:将内存分成较小的块以munmap较小的块(这种情况可能吗?),或者根本不使用munmap,自己分配/释放内存,如果文件不再存在于文件系统中,则可选地缓存内存块,并将其重复使用于下一个文件。
感谢任何想法。

调整线程优先级可能会有帮助。 - blueshift
实际上,工作线程使用优先级为50的SCHED_RR调度策略,因此它们应该被优先考虑。 - mehturt
您是否需要在内存映射的存储中进行写入以修改文件? - rodrigo
你能更具体地说明一下“当文件不再存在于文件系统中”以及你的mmap()参数(共享/私有,保护)吗? - Yann Droneaud
@ydroneaud 当我在文件系统上找到要处理的文件时,我使用mmap()函数(实际上,该文件位于tmpfs文件系统上,不知道是否有区别);prot参数设置为PROT_READ,flags参数设置为MAP_SHARED | MAP_POPULATE;虽然我也可以使用MAP_PRIVATE。我只需要读取文件内容。当其他进程从文件系统中删除该文件,并且我的应用程序完成处理后,我会调用munmap()和close()函数来关闭相应的文件描述符。 - mehturt
显示剩余2条评论
4个回答

3
实际上导致它变慢的原因是munmap()在整个系统调用期间都会获取mm->mmap_sem锁定。其他多个操作也可能被阻塞,例如(但不仅限于)fork()/mmap()。尤其需要注意的是,在不实现对已在内存中的页面进行无锁get_user_pages_fast()操作的架构中,这一点尤为重要,因为一堆futex操作(支持pthread基元)将调用get_user_pages_fast(),而默认实现将尝试对mmap_sem进行读锁定。

1
谢谢。有哪些架构可能没有实现无锁的get_user_pages_fast()操作(用于已经在内存中的页面)? - mehturt

0
我最终采取的措施(并且证明是足够的)是将大内存块分片进行munmap处理,例如,我有一个500MB的内存块,并且我按照100MB的大小进行munmap处理。

0

如果你正在顺序读取内存,请尝试定期使用posix_madvise()函数,并在读取的内存页面上使用MADV_DONTNEED标志。请参考posix_madvise()

在Linux下,也可以使用madvise()函数。请参考madvise()


工作线程可以随机访问内存,所以我不能这样做。在munmap()之前,我可以使用madvise()和MADV_DONTNEED,但我觉得这没有意义,对吗?或者我应该尝试在munmap()之前多次调用madvise()来处理内存区域的不同部分? - mehturt
1
@mehturt 在调用 munmap() 之前没有必要再调用 madvise(MADV_DONTNEED),在这种情况下,它是隐含的。 - Yann Droneaud

0
当文件不再存在于文件系统上时,执行munmap操作。
所以当文件从文件系统中取消链接时,你调用munmap。然后,可能导致系统变慢的是实际删除inode的过程,这是在所有目录条目、文件描述符和内存映射被释放时完成的。
在Linux(ext3)中,已知删除性能存在问题。如果是这种情况,您可以尝试切换到ext4(使用extents),如果在您的场景中可行的话。
另一个选择是在其他目录中创建硬链接,这样当你munmap它们时,它们并不真正被删除。然后,你可以调用ionice -c 3 rm 或类似的命令在后台实际删除它们...

文件存储在tmpfs文件系统上。实际上,文件是由其他进程删除的,我的进程只对底层文件描述符执行munmap()和close()操作。 - mehturt
另一个进程执行unlink操作,但正是这个进程实际上删除了inode,并释放了对它的最后一个引用。你可以尝试手动创建一些这样的文件,并使用time rm命令来查看删除所需的时间。 - rodrigo
是的,我的问题是是否有可能这样做,以确保其他线程不受影响。 - mehturt

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