fisher (raa) wrote,
fisher
raa

память - это наше всё?

программистское.
Давно хотел провести маленькое исследование по расходу памяти Perl & PHP. Результаты ничего особенного не значат, но забавно. Итак, читаем 90000 строк из базы, создаем в мозгах массив массивов из слов (('мама'),('папа') ...).
Закрываем все соединения, подчищаем mysql-структуры, считаем память:


PHP-code:
pid = getmypid();
$out = '';
exec("ps --pid $pid --no-headers -o%mem,rss,pid",$out);
$mem_usage_str = join('',$out);
$mem_usage_data = split(' ',trim($mem_usage_str));
$before_kbytes = $mem_usage_data[1];
echo 'memory usage before:'.$mem_usage_str."\n";

$dbh = mysql_connect('127.0.0.1','fisher','***');

if(!$dbh) {
    die('unable to connect to db');
}

echo "loading...\n";
$result = mysql_query('SELECT * FROM test.words_ru',$dbh);
if(!$result || $dbh->error) {
    die('empty result; db->error = '.$dbh->error);
}

$array = array();
while($row = mysql_fetch_array($result,MYSQL_NUM)) {
    $size += strlen($row[0]);
    $array[] = $row;
}

mysql_free_result($result);
mysql_close();

echo "loaded: ".count($array)."\n";
unset($out);
exec("ps --pid $pid --no-headers -o%mem,rss,pid",$out);
$mem_usage_str = join('',$out);
$mem_usage_data = split(' ',trim($mem_usage_str));
$after_kbytes = $mem_usage_data[1];
echo 'memory usage after:'.$mem_usage_str."\n";

echo "size(bytes):".$size."\n";
echo "diff(bytes):".(1024*($after_kbytes - $before_kbytes))."\n";


Perl-code (за качество кода прошу не пинать, активно не писал года 4 уже):
!/usr/bin/perl -w

use strict;
use DBI;

my $pid = $$;
print "memory usage before:";
my $mem_usage_str = `ps --pid $pid --no-headers -o%mem,rss,pid`;
print $mem_usage_str;
my @mem_usage_data = split(' ',$mem_usage_str);
my $before_kbytes = $mem_usage_data[1];

my $dbh = DBI->connect(
    'DBI:mysql:database=test;host=localhost',
    'fisher','***',{'RaiseError'=>1}
);

my $cursor = $dbh->prepare('SELECT word FROM words_ru');
unless($cursor) {
    die $dbh->errstr;
}

unless($cursor->execute()) {
    die $cursor->errstr;
}

print "loading...\n";
my $array_ref = $cursor->fetchall_arrayref();
my $n_array_ref = scalar(@$array_ref);
print "loaded ".$n_array_ref."\n";

$cursor->finish();
$dbh->disconnect();

my $size = 0;
for(my $i=0; $i<$n_array_ref; $i++) {
    $size += length($array_ref->[$i]->[0]);
}

print "memory usage after:";
$mem_usage_str = `ps --pid $pid --no-headers -o%mem,rss,pid`;
print $mem_usage_str;
@mem_usage_data = split(' ',$mem_usage_str);
my $after_kbytes = $mem_usage_data[1];

print "size(bytes):".$size."\n";
print "diff(bytes):".1024*($after_kbytes - $before_kbytes)."\n";


Results:
fisher@fisher:~/tmp> ./memtest.pl
memory usage before: 0.3 3140  7801
loading...
loaded 92673
memory usage after: 1.8 18968 7801
size(bytes):889820
diff(bytes):16207872
fisher@fisher:~/tmp> ./memtest.php
memory usage before: 0.2 2724  7825
loading...
loaded: 92673
memory usage after: 3.3 34272 7825
size(bytes):889820
diff(bytes):32305152

Тихо фигеем и делаем предположение, что дело наверное не столько в zval, сколько в "жадности" при следующих аллоках, проэтому ставим лимиты в SQL.
LIMIT = 20000:
fisher@fisher:~/tmp> ./memtest.php
memory usage before: 0.2 2724  8130
loading...
loaded: 20000
memory usage after: 0.9 9696  8130
size(bytes):188414
diff(bytes):7139328
fisher@fisher:~/tmp> ./memtest.pl
memory usage before: 0.3 3144  8136
loading...
loaded 20000
memory usage after: 0.6 6960  8136
size(bytes):188414
diff(bytes):3907584

LIMIT=10000
fisher@fisher:~/tmp> ./memtest.php
memory usage before: 0.2 2724  8148
loading...
loaded: 10000
memory usage after: 0.6 6308  8148
size(bytes):94247
diff(bytes):3670016
fisher@fisher:~/tmp> ./memtest.pl
memory usage before: 0.3 3140  8154
loading...
loaded 10000
memory usage after: 0.5 5300  8154
size(bytes):94247
diff(bytes):2211840


То же самое - просто делаем строки разной длины, пропорции примерно те же.

Почему вообще могут быть сильные различия:
- оба используют разные механизмы аллоцирования следующих блоков, возможно PHP в этом смысле просто пытается захавать побольше, когда понимает, что памяти недостаточно. Но экспериментом это не очень подтверждается - по памяти монотонно ползем вверх при увеличении размера массива (конечно, надо бы график нормальный построить, но очень в лом)
- поскольку внутри данные представлены по-разному, требуется различное количество памяти на поддержание своих внутренних структур (zval и проч.). И похоже, дело именно в них.

Ваши соображения? Может, я чего не учел?

P.S. насколько я понимаю, выигрыш С/C++ как раз будет примерно такой, какой получается разница size и diff. Нефиговые такие 50 раз, да?
Update: tony2001 делает абсолютно верную поправку - ниже более точная оценка

Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 4 comments