免责声明我不确定我使用的术语是否正确。可能不是由optree引起下面所述的膨胀:可能是DynaLoader
加载的符号未释放。
是否可以使用模块,例如POSIX.pm
,将其卸载并减少(缩小或修剪)optree,而无需
我尝试过的事情
Class::Unload->unload('POSIX');
Symbol::delete_package('POSIX');
no POSIX;
这是一个简单的测试,创建一个文件test.pl
$|++;
use Symbol;
use Class::Unload;
use POSIX;
print "GOT POSIX";
sleep(3);
no POSIX;
Class::Unload->unload('POSIX');
Symbol::delete_package('POSIX');
print "unloaded";
sleep(3);
Shell命令
perl ./test.pl & watch -n1 'ps -C perl -o "cmd rss";'
您可能会或可能不会看到RSS大小的增加(POSIX可能会在
watch
产生ps
之前加载)。但是,我希望看到它缩小。跟踪
POSIX.pm
到底能看到什么,我使用 XSLoader
来使用 DynaLoader
。在
/proc/$$/smaps
中进行一些快速的比较检查,我已经确定使用POSIX.pm会导致代表空间差异的堆分配。使用POSIX.pm时,堆上的第一个分配要大得多:56122fe4c000-561230040000 rw-p 00000000 00:00 0 [heap]
Size: 2000 kB
Rss: 1956 kB
Pss: 1956 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 1956 kB
Referenced: 1956 kB
Anonymous: 1956 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac sd
与
560c9f6ba000-560c9f6fc000 rw-p 00000000 00:00 0 [heap]
Size: 264 kB
Rss: 220 kB
Pss: 220 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 220 kB
Referenced: 220 kB
Anonymous: 220 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac sd
我已经确认了几件事,对 namespace 进行操作并不会将打开的文件句柄放到
POSIX.so
和Fnctl.so
中-我是通过lsof
确定的。这本身有点令人担忧。我认为在被调用者的程序包上分配句柄是有意义的。 XSLoader
也使您无法释放该文件句柄-DynaLoader
中提供了一项功能。此外,似乎在
libc
/dlfcn.h
中,我有因此,我猜测这可能是令人怀疑的,
DynaLoader::dl_unload_file
正在调用 dlclose
,它似乎确实有效。foreach my $dlref ( @DynaLoader::dl_librefs ) {
print DynaLoader::dl_unload_file($dlref);
}
在通过上述操作对所有加载了
DynaLoader
和XSLoader
的文件进行核对之后,RSS仍然没有删除。 最佳答案
一般来说,没有。棘手的细节是几乎没有人缩减自己的内存,因为几乎每个人都使用C库malloc
(和 friend )调用来直接或间接地分配内存。而且,没有(标准的)方法可以告诉C库释放内存(将其发送回OS)。 Perl在这里没有什么不同-一旦malloc
ed和free
d,Perl依赖的C库保留内存以备将来使用,因此,如果您需要重用内存,则不需要昂贵的内核调用(特别是brk
),可以简单地重用。实际上,这就是您的卸载方案正在做的事情-当您返回并在其余服务器进程中重复使用下一个2MB内存时,您将重新使用内存,而不是调用brk
,那么您就可以快点。
如果您接管了内存分配所有权并自己调用brk
,则可以这样做,但这很少值得。要使perl使用该分配器,就需要对perl和重新编译进行一些代码更改。可能不是您想做的。
其他选择是要么硬着头皮,在 fork 任何服务器之前加载POSIX(这应该将所有内容保留在共享的写时复制内存中,因此对于5k服务器仅占用2MB的内存),或者 fork 加载在 child 中使用POSIX,进行肮脏的工作,退出 child ,然后继续在 parent 中工作。对我来说,这似乎相对较慢。