3

我正在开发一个并行应用程序(C,pthread)。我跟踪了系统调用,因为在某些时候我的并行性能很差。我的跟踪显示我的程序调用mprotect()了很多次......足以显着减慢我的程序。

我确实分配了很多内存(使用malloc()),但只有合理数量的调用brk()来增加堆大小。那么为什么会有这么多电话mprotect()呢?!

4

4 回答 4

3

您是否正在创建和销毁大量线程?

大多数 pthread 实现在分配线程堆栈时会添加一个“保护页面”。这是一个访问受保护的内存页面,用于检测堆栈溢出。我希望每次创建或终止线程以(取消)保护保护页面时至少调用一次 mprotect 。如果是这种情况,有几个明显的策略:

  1. pthread_attr_setguardsize()在创建线程之前使用将保护页面大小设置为零。
  2. 使用线程池(与处理器说的一样多的线程)。线程完成任务后,将其返回到池中以获取新任务,而不是终止并创建新线程。

另一种解释可能是,如果检测到溢出,您所在的平台将增加线程堆栈。我不认为这是在 Linux 上使用 GCC/Glibc 实现的,但最近有一些类似的提议。如果您在处理时使用大量堆栈空间,则可以使用pthread_attr_setstacksize.

或者它可能完全是别的东西!

于 2009-05-12T02:39:14.530 回答
2

如果可以,请在调试 libc 下运行程序并在 mprotect() 上中断。查看调用堆栈,查看导致 mprotect() 调用的代码在做什么。

于 2009-05-11T11:35:31.360 回答
2

将 ptmalloc2 用于 malloc 的 glibc 库在内部使用 mprotect() 对主线程以外的线程的堆进行微管理(对于主线程,使用 sbrk() 代替。) malloc() 首先使用 mmap() 分配大块内存如果堆区域似乎有争用,则线程,然后它更改不必要部分的保护位以使其可以使用 mprotect() 访问。稍后,当它需要增加堆时,它会再次使用 mprotect() 将保护更改为读/写。这些 mprotect() 调用用于多线程应用程序中的堆增长和收缩。

http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf 以更详细的方式解释了这一点。

于 2011-10-10T19:27:22.200 回答
0

“valgrind”套件有一个名为“callgrind”的工具,它会告诉你什么叫什么。如果您在“callgrind”下运行应用程序,则可以使用“kcachegrind”查看生成的配置文件数据(它可以分析由“cachegrind”或“callgrind”制作的配置文件)。然后只需双击左窗格中的“mprotect”,它就会显示调用它的代码和次数。

于 2011-08-14T17:50:18.077 回答