调用mprotect的次数过多

时间:2009-05-11 09:58:19

标签: c multithreading parallel-processing system-calls

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

我确实分配了大量内存(使用malloc()),但只有合理数量的调用brk()才能增加堆大小。那么为什么这么多人打电话给mprotect()

4 个答案:

答案 0 :(得分:3)

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

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

  1. 在创建线程之前使用pthread_attr_setguardsize()将防护页面大小设置为零。
  2. 使用线程池(与处理器一样多的线程)。一旦线程完成任务,将其返回到池中以获取新任务而不是终止并创建新线程。
  3. 另一种解释可能是你在一个平台上,如果检测到溢出,就会增加线程的堆栈。我不认为这是在具有GCC / Glibc的Linux上实现的,但最近有这些方面提出了一些建议。如果在处理过程中使用大量堆栈空间,则可以使用pthread_attr_setstacksize显式增加初始/最小堆栈大小。

    或者它可能完全是另一回事!

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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