O calcanhar de Aquiles do Linux sempre foi o gerenciamento de memória. Por mais memória que se tenha disponível, ele vorazmente sempre quer mais. E nunca libera a memória livre.
E meus parcos 6 GB de memória do laptop tem sentido isso nesses últimos dias de 2012. E verificável pelos gráficos do Munin, que mostra o pedido de 10 GB de memória pra usar. Isso me faz pensar que talvez os Maias esteja certos.
Eu ainda não descobri qual programa (ou processo) está causando isso, e o kernel Linux não cuida de matar o processo comilão.
Então criei um pequeno daemon, em perl, para ficar lendo o /proc e matando os processos que mais consomem memória se a carga do sistema aumentar muito (atualmente marquei para load average maior de 10).
#! /usr/bin/perl
use POSIX;
$PROC = "/proc";
$MAXLOAD = 10; #loadaverage
$SLEEPTIME = 1; #seconds
if (getuid() != 0) {
print "Only root can run this program.\n";
exit(1);
}
if (! -d $PROC) {
print "Not possible to run. System not running with $PROC directory\n";
exit(1);
}
sub GetMem() {
$pid_dir = $_[0];
my $dir = $PROC."/".$pid_dir."/statm";
open(MEM, $dir) or die "Error:$dir $!\n";
@params = split(/ /, );
close MEM;
$memory = $params[0];
return $memory;
}
sub GetPID() {
my %MEM;
opendir(PROC,$PROC) or die "Not possible to run. System not running with $PROC directory\n";
foreach $dir (readdir PROC) {
# Just read higher processes
# avoid init (1) or non-pid
next if ($dir !~ m/^\d\d\d+/);
$mem = &GetMem($dir);
if ($mem) {
$MEM{$dir} = $mem;
}
}
closedir PROC;
return %MEM;
}
sub GetLoad() {
open(LOAD,$PROC."/loadavg") or die "Impossible to detect load average by $PROC:$!\n";
my $load = ;
close LOAD;
my @params = split(/ /, $load);
return $params[0];
}
sub GetCommand() {
my $pid = $_[0];
open(CMD, $PROC."/".$pid."/cmdline") or die "Impossible to read the source command: $!\n";
my $cmd = ;
close CMD;
return $cmd;
}
sub DaemonizeMe() {
print "Starting to memory control daemon\n";
POSIX::setsid or die "setsid: $!";
my $pid = fork ();
if ($pid < 0) {
die "fork: $!";
} elsif ($pid) {
exit 0;
}
chdir "/";
umask 0;
foreach (0 .. (POSIX::sysconf (&POSIX::_SC_OPEN_MAX) || 1024)) {
POSIX::close $_;
}
open (STDIN, "/dev/null");
#open (STDERR, ">&STDOUT");
}
&DaemonizeMe();
my $mypid = getpid();
my %DEATHCOUNTER;
while (! $SIG{TERM}) {
sleep($SLEEPTIME);
my $load = &GetLoad();
next if ($load < $MAXLOAD);
my %MEM;
%MEM = &GetPID();
$higher_m = 0;
$higher_pid = 0;
foreach $k (sort keys %MEM) {
next if ($k eq $mypid);
$mem = $MEM{$k};
if ($mem > $higher_m) {
$higher_m = $mem;
$higher_pid = $k;
$DEATHCOUNTER{$higher_pid}++;
}
}
if ($DEATHCOUNTER{$higher_pid} >= 5) {
print "Killing due higher memory usage: ".&GetCommand($higher_pid)." (".$higher_pid.") [".$higher_m." Bytes]\n";
%DEATHCOUNTER;
}
}
print "Exiting...";
exit(0);
Os Maias podiam até estar certos, mas isso não significa que precisamos ficar sentados olhando.