4

我写了一个小程序并在 Solaris/Linux 平台下编译它来衡量将这段代码应用到我的应用程序的性能。

该程序是这样编写的,最初使用sbrk(0)系统调用,我取了堆区域的基地址。之后我使用系统调用分配了 1.5 GB 的内存malloc,然后我使用memcpy系统调用将 1.5 GB 的内容复制到分配的内存区域。然后,我释放了分配的内存。

释放后,我sbrk(0)再次使用系统调用查看堆大小。

这是我有点困惑的地方。在 Solaris 中,即使我释放了分配的内存(接近 1.5 GB),进程的堆大小仍然很大。但是我在Linux中运行同样的应用程序,释放后发现进程的堆大小等于分配1.5 GB之前的堆内存大小。

我知道 Solaris 不会立即释放内存,但我不知道如何调整 Solaris 内核以在free()系统调用后立即释放内存。

为什么我在Linux下没有同样的问题?

4

1 回答 1

4

我得到了我所问问题的答案。

应用程序内存分配器:

C 和 C++ 开发人员必须手动管理内存分配和释放内存。默认内存分配器位于 libc 库中。

Libc 请注意,在执行 free() 之后,释放的空间可供应用程序进一步分配,而不是返回给系统。只有当应用程序终止时,内存才会返回给系统。这就是为什么应用程序的进程大小通常永远不会减少的原因。但是对于长时间运行的应用程序,应用程序进程大小通常保持在稳定状态,因为释放的内存可以被重用。如果不是这种情况,那么很可能是应用程序正在泄漏内存,即分配的内存已使用但在不再使用时从未释放,并且指向已分配内存的指针没有被应用程序跟踪 - 基本上丢失了。

当并发 malloc 或 free 操作频繁发生时,libc 中的默认内存分配器不适用于多线程应用程序,特别是对于多线程 C++ 应用程序。这是因为创建和销毁 C++ 对象是 C++ 应用程序开发风格的一部分。当使用默认的 libc 分配器时,堆由单个堆锁保护,由于 malloc 或空闲操作期间的严重锁争用,导致默认分配器无法针对多线程应用程序进行扩展。使用 Solaris 工具很容易检测到此问题,如下所示。

首先,使用 prstat -mL -p 查看应用程序是否在锁上花费了很多时间;看LCK专栏。例如:

-bash-3.2# prstat -mL -p 14052
   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID
 14052 root     0.6 0.7 0.0 0.0 0.0  35 0.0  64 245  13 841   0 test_vector_/721
 14052 root     1.0 0.0 0.0 0.0 0.0  35 0.0  64 287   5 731   0 test_vector_/941
 14052 root     1.0 0.0 0.0 0.0 0.0  35 0.0  64 298   3 680   0 test_vector_/181
 14052 root     1.0 0.1 0.0 0.0 0.0  35 0.0  64 298   3  1K   0 test_vector_/549
 ....

它显示应用程序花费大约 35% 的时间等待锁定。

然后,使用 plockstat(1M) 工具查找应用程序正在等待的锁。例如,使用进程 ID 14052 跟踪应用程序 5 秒,然后使用 c++filt 实用程序过滤输出,以消除 C++ 符号名称。(Sun Studio 软件提供了 c++filt 实用程序。)如果应用程序不是 C++ 应用程序,则不需要通过 c++filt 进行过滤。

-bash-3.2#  plockstat -e 5 -p 14052 | c++filt
Mutex block
Count     nsec   Lock                         Caller
-------------------------------------------------------------------------------
 9678 166540561 libc.so.1‘libc_malloc_lock   libCrun.so.1‘void operator 
 delete(void*)+0x26

 5530 197179848 libc.so.1‘libc_malloc_lock   libCrun.so.1‘void*operator 
 new(unsigned)+0x38

......

从前面的内容中,您可以看到堆锁 libc_malloc_lock 的竞争非常激烈,这可能是导致扩展问题的一个原因。libc 分配器的这种缩放问题的解决方案是使用改进的内存分配器,例如 libumem 库。

另请访问:http: //developers.sun.com/solaris/articles/solaris_memory.html

感谢所有试图回答我的问题的人,Santhosh。

于 2010-06-03T06:28:01.027 回答