Disclaimer I'm not sure I'm using the right terms. It may not be the optree responsible for the bloat mentioned below: it may be the symbols loaded by DynaLoader
that are not freed.
Is it possible to use a module, like POSIX.pm
, unload it and lessen (shrink, or prune) the optree without either
- Rexecing perl
- Forking
Things I've tried,
Here is an easy test create a file 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 command
perl ./test.pl & watch -n1 'ps -C perl -o "cmd rss";'
You may or may not be able to see the RSS size increase (POSIX may load before watch
spawns ps
). But, I want to see it shrink back down.
Tracking down what exactly POSIX.pm
does I see it uses XSLoader
which uses DynaLoader
.
Doing some quick comparative checks in /proc/$$/smaps
I've determined that using POSIX.pm causes a heap allocation that represents the difference in space. The first allocation on the heap, is massively bigger when using 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
vs
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
I've confirmed a few things, nuking the namespace does not drop the open file handle to POSIX.so
and Fnctl.so
-- I determined this with lsof
. That is in itself somewhat concerning. I would think it would make sense to allocate the handle on the callee's package. XSLoader
also obscures that you can release that file handle -- a feature available in DynaLoader
.
Further, it seems that in libc
/ dlfcn.h
I have
dlclose()
The function dlclose() decrements the reference count on the dynamically loaded shared object referred to by handle. If the reference count drops to zero, then the object is unloaded. All shared objects that were automatically loaded when dlopen() was invoked on the object referred to by handle are recursively closed in the same manner.
A successful return from dlclose() does not guarantee that the symbols associated with handle are removed from the caller's address space. In addition to references resulting from explicit dlopen() calls, a shared object may have been implicitly loaded (and reference counted) because of dependencies in other shared objects. Only when all references have been released can the shared object be removed from the address space.
So I'm guessing that may be suspect, DynaLoader::dl_unload_file
is calling dlclose
and it does seems to work.
foreach my $dlref ( @DynaLoader::dl_librefs ) {
print DynaLoader::dl_unload_file($dlref);
}
After I nuked all files loaded with DynaLoader
and XSLoader
by doing the above the RSS still did not drop.
POSIX
a specific problem? There are alternatives to most of the functions in that module. I would have thought addressing the problem head on would involve removing duplicate data, rather than minimising a specific overhead within each one. Why do you want to avoidfork
? – Xylem