perl memória szivárgás kikerülése

Szervusztok!

Egy kiragadott részlettel is (lentebb) sikerült előállítanom azt, hogy egy adathalmot olvasva, majd kicsit gereblyézve, folyamatosan nő a memória igénye a perl-nek. Próbálom a lehetőségeket számításba venni, de az utolsó találatnál megállt bennem minden.

- adatbázis
- undef @var;
- @var = ();
- perldoc -q "program shrinks"

Segítsetek kikerülni ebből, amit köszönök előre is!
Üdv,
vfero


#!/usr/bin/perl -w

use utf8;
use strict;
use locale;
use Switch;
use English;
use warnings;
use Env qw(@HOME $USER);
use Data::Dump::Streamer;
use List::MoreUtils qw(uniq);
use Term::ReadKey;
use List::Util qw(min max);
#---------------------------------------------
sub checkLimit($$$){
my ($p_a,$p_limit,$p_res) = @_;

foreach (@{$p_a}){
if($_ > ${$p_limit}){ push(@{$p_res}, $_) };
}
}
#---------------------------------------------
# MAIN
my @a = ();

# fill
for(my $c=0 ; $c < 100000 ; $c++){

$a[$c] = rand();
if(($c % 10000)==0) {print $c . "\n"}
}

my $limit;
my @res;

printf("Data filled %s, check the memory. ex.: memstat -w -p %s\n",$#a,$PID); ReadKey(0);

# check
foreach $limit(map { 0.01 * $_ } 1..100 ){

checkLimit(\@a,\$limit,\@res);

printf("limit %0.3f count %d\n",$limit, $#res );
@res=();
}
undef @res;

printf("Pls check again the memory usage. ex.: memstat -w -p %s\n",$PID); ReadKey(0);
exit ;
__END__

first

17012k: PID 1098 (/usr/bin/perl)
4352k( 0k): /usr/lib/locale/locale-archive 1098
16k( 8k): /usr/bin/perl 1098
3620k( 1536k): /usr/lib/libperl.so.5.18.2 1098
2068k( 12k): /usr/lib/perl/5.18.2/auto/Fcntl/Fcntl.so 1098
2064k( 12k): /usr/lib/perl/5.18.2/auto/Hash/Util/Util.so 1098
2068k( 16k): /usr/lib/perl/5.18.2/auto/IO/IO.so 1098
2380k( 328k): /usr/lib/perl/5.18.2/auto/re/re.so 1098
2076k( 20k): /usr/lib/perl/5.18.2/auto/List/Util/Util.so 1098
2084k( 32k): /usr/lib/perl/5.18.2/auto/Data/Dumper/Dumper.so 1098
2064k( 12k): /usr/lib/perl/5.18.2/auto/Filter/Util/Call/Call.so 1098
2060k( 8k): /usr/lib/perl/5.18.2/auto/Tie/Hash/NamedCapture/NamedCapture.so 1098
2120k( 60k): /usr/lib/perl/5.18.2/auto/B/B.so 1098
2080k( 28k): /usr/lib/perl5/auto/Term/ReadKey/ReadKey.so 1098
2064k( 12k): /usr/lib/perl5/auto/B/Utils/Utils.so 1098
2080k( 28k): /usr/lib/perl5/auto/Data/Dump/Streamer/Streamer.so 1098
2068k( 16k): /usr/lib/perl5/auto/PadWalker/PadWalker.so 1098
2128k( 72k): /usr/lib/perl5/auto/List/MoreUtils/MoreUtils.so 1098
3096k( 1044k): /lib/x86_64-linux-gnu/libm-2.19.so 1098
2064k( 12k): /lib/x86_64-linux-gnu/libdl-2.19.so 1098
2092k( 36k): /lib/x86_64-linux-gnu/libcrypt-2.19.so 1098
2152k( 100k): /lib/x86_64-linux-gnu/libpthread-2.19.so 1098
148k( 140k): /lib/x86_64-linux-gnu/ld-2.19.so 1098
3840k( 1768k): /lib/x86_64-linux-gnu/libc-2.19.so 1098
--------
67796k ( 5300k)

second

23804k: PID 1098 (/usr/bin/perl)
4352k( 0k): /usr/lib/locale/locale-archive 1098
16k( 8k): /usr/bin/perl 1098
3620k( 1536k): /usr/lib/libperl.so.5.18.2 1098
2068k( 12k): /usr/lib/perl/5.18.2/auto/Fcntl/Fcntl.so 1098
2064k( 12k): /usr/lib/perl/5.18.2/auto/Hash/Util/Util.so 1098
2068k( 16k): /usr/lib/perl/5.18.2/auto/IO/IO.so 1098
2380k( 328k): /usr/lib/perl/5.18.2/auto/re/re.so 1098
2076k( 20k): /usr/lib/perl/5.18.2/auto/List/Util/Util.so 1098
2084k( 32k): /usr/lib/perl/5.18.2/auto/Data/Dumper/Dumper.so 1098
2064k( 12k): /usr/lib/perl/5.18.2/auto/Filter/Util/Call/Call.so 1098
2060k( 8k): /usr/lib/perl/5.18.2/auto/Tie/Hash/NamedCapture/NamedCapture.so 1098
2120k( 60k): /usr/lib/perl/5.18.2/auto/B/B.so 1098
2080k( 28k): /usr/lib/perl5/auto/Term/ReadKey/ReadKey.so 1098
2064k( 12k): /usr/lib/perl5/auto/B/Utils/Utils.so 1098
2080k( 28k): /usr/lib/perl5/auto/Data/Dump/Streamer/Streamer.so 1098
2068k( 16k): /usr/lib/perl5/auto/PadWalker/PadWalker.so 1098
2128k( 72k): /usr/lib/perl5/auto/List/MoreUtils/MoreUtils.so 1098
3096k( 1044k): /lib/x86_64-linux-gnu/libm-2.19.so 1098
2064k( 12k): /lib/x86_64-linux-gnu/libdl-2.19.so 1098
2092k( 36k): /lib/x86_64-linux-gnu/libcrypt-2.19.so 1098
2152k( 100k): /lib/x86_64-linux-gnu/libpthread-2.19.so 1098
148k( 140k): /lib/x86_64-linux-gnu/ld-2.19.so 1098
3840k( 1768k): /lib/x86_64-linux-gnu/libc-2.19.so 1098
--------
74588k ( 5300k)

Hozzászólások

Szervusztok!

Átírtam hash-re kíváncsiságképp, sajnos így még rosszabb a helyzet. :(
Erősen elgondolkodtat a perl így, mert ilyen memória kezeléssel ez nem használható értelmesen semmire sem.
Ti ezt miképp látjátok?
Kösz,
vfero


#!/usr/bin/perl -w

use utf8;
use strict;
use locale;
use Switch;
use English;
use warnings;
use Env qw(@HOME $USER);
use Data::Dump::Streamer;       # libdata-dump-streamer-perl
use List::MoreUtils qw(uniq);
use Term::ReadKey;
use List::Util qw(min max);
#---------------------------------------------
sub checkLimit($$$){
my ($p_a,$p_limit,$p_res) = @_;

foreach (@{$p_a}){
if($_ > ${$p_limit}){
  $p_res->{"no"} = $p_res->{"no"} + 1;
  $p_res->{  $p_res->{"no"}  } = $_;
  }
}
}
#---------------------------------------------
# MAIN
my @a = ();
# fill
for(my $c=0 ; $c < 100000 ; $c++){

$a[$c] = rand();
if(($c % 10000)==0) {print $c . "\n"}
}

my $limit;
my %res;

printf("Data filled %s, check the memory. ex.: memstat -w -p %s\n",$#a,$PID); ReadKey(0);

# check
%res->{"no"}=0;
foreach $limit(map { 0.01 * $_ } 1..100 ){
  checkLimit(\@a,\$limit,\%res);
  printf("limit %3.3f res %d\n",$limit, %res->{"no"} );
  %res->{"no"}=0;
  }
undef %res;

printf("Pls check again the memory usage. ex.: memstat -w -p %s\n",$PID); ReadKey(0);
exit ;
__END__

first

  17092k: PID 16450 (/usr/bin/perl)
   2064k(     12k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Filter/Util/Call/Call.so 16450
   2088k(     36k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Data/Dumper/Dumper.so 16450
   2060k(      8k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Tie/Hash/NamedCapture/NamedCapture.so 16450
   2124k(     64k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/B/B.so 16450
   2080k(     28k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/Data/Dump/Streamer/Streamer.so 16450
   2072k(     16k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/PadWalker/PadWalker.so 16450
   2148k(     96k): /lib/x86_64-linux-gnu/libpthread-2.19.so 16450
    136k(    128k): /lib/x86_64-linux-gnu/ld-2.19.so 16450
   3740k(   1672k): /lib/x86_64-linux-gnu/libc-2.19.so 16450
   2084k(     32k): /lib/x86_64-linux-gnu/libcrypt-2.19.so 16450
   2064k(     12k): /lib/x86_64-linux-gnu/libdl-2.19.so 16450
   3076k(   1024k): /lib/x86_64-linux-gnu/libm-2.19.so 16450
   2080k(     28k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/Term/ReadKey/ReadKey.so 16450
     16k(      8k): /usr/bin/perl 16450
   1572k(      0k): /usr/lib/locale/locale-archive 16450
   2064k(     12k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/B/Utils/Utils.so 16450
   2128k(     76k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/List/MoreUtils/MoreUtils.so 16450
   2428k(    376k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/re/re.so 16450
   2088k(     36k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/List/Util/Util.so 16450
   2064k(     12k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Hash/Util/Util.so 16450
   2068k(     12k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Fcntl/Fcntl.so 16450
   2068k(     16k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/IO/IO.so 16450
   3844k(   1756k): /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2 16450
--------
  65248k (   5460k)

second

  30952k: PID 16450 (/usr/bin/perl)
   2064k(     12k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Filter/Util/Call/Call.so 16450
   2088k(     36k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Data/Dumper/Dumper.so 16450
   2060k(      8k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Tie/Hash/NamedCapture/NamedCapture.so 16450
   2124k(     64k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/B/B.so 16450
   2080k(     28k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/Data/Dump/Streamer/Streamer.so 16450
   2072k(     16k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/PadWalker/PadWalker.so 16450
   2148k(     96k): /lib/x86_64-linux-gnu/libpthread-2.19.so 16450
    136k(    128k): /lib/x86_64-linux-gnu/ld-2.19.so 16450
   3740k(   1672k): /lib/x86_64-linux-gnu/libc-2.19.so 16450
   2084k(     32k): /lib/x86_64-linux-gnu/libcrypt-2.19.so 16450
   2064k(     12k): /lib/x86_64-linux-gnu/libdl-2.19.so 16450
   3076k(   1024k): /lib/x86_64-linux-gnu/libm-2.19.so 16450
   2080k(     28k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/Term/ReadKey/ReadKey.so 16450
     16k(      8k): /usr/bin/perl 16450
   1572k(      0k): /usr/lib/locale/locale-archive 16450
   2064k(     12k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/B/Utils/Utils.so 16450
   2128k(     76k): /usr/lib/x86_64-linux-gnu/perl5/5.20/auto/List/MoreUtils/MoreUtils.so 16450
   2428k(    376k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/re/re.so 16450
   2088k(     36k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/List/Util/Util.so 16450
   2064k(     12k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Hash/Util/Util.so 16450
   2068k(     12k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/Fcntl/Fcntl.so 16450
   2068k(     16k): /usr/lib/x86_64-linux-gnu/perl/5.20.2/auto/IO/IO.so 16450
   3844k(   1756k): /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2 16450
--------
  79108k (   5460k)

Szia,
Ez azóta tudott, hogy a perl létezik ;)
http://stackoverflow.com/questions/12619797/memory-management-in-perl
http://www.perlmonks.org/?node_id=803515
A perl alapvetően az OS kedvéért majd elengedi a memóriát, ha már túl sokat eszik, de addig fenntartja.
Ami igazából, tekintve egy interpretált nyelvről beszélünk, ahol nem ismert előre a várható erőforrás igény, sőt, még a futás hossz és a futtatandó kód mennyiség sem becsülhető, teljesen megérthető viselkedés.
Ha attól félsz, hogy kiéhezteti a rendszer többi komponensét, nem kell aggódnod. Amikor kell az OS-nek, az interpreter elengedi a szabad memóriát, ehhez csak az kell, hogy szépen felszabadítsd azt, ami neked már nem kell. A többit az interpreter el fogja intézni.
Üdv,
LuiseX

Szia,
Tudtommal a perl interpreter szépen elengedi a neki nem kellő területeket, ha már nem használja ÉS az OS-nek kellhet (vagyis a perl veszélyezteti az OS működését).
És nem egészen standard malloc-ról beszélünk, főleg, mivel a Perl memória foglalása dinamikusan történik, nem pedig előre, statikusan.
Ahogy használod a változókat, és nem szabadítod fel őket [perlben], úgy fogják szép lassan felzabálni a memóriát, és ahogy elengeded őket, úgy fogja a perl újrahasznosítani a korábbi területeket.
(mondjuk, kicsit elvetemültebb a koncepciója, mivel valójában refekkel dolgozik a belső világa, és az azonos területre mutató ref countot nézi, mielőtt felszabadít, de talán ezt tekinthetjük a koncepció ezen szemszögéből mellékesnek :) )
Üdv,
LuiseX

Szia,
Igen, sajnos ezt nem tudtam szépen megfogalmazni :D Mentségemre vállják, még csak 10 perce jutottam el a kávéig :D
A perl interpreter menet közben találja ki, hogy kell-e még foglalni, nem pedig előre teszi meg... Ugyanígy az interpreter eldönti majd, hogy akkor nekünk kell-e még memória, vagy az OS-nek adja inkább vissza. Ebbe a perlben fejlesztőnek egyszerűen nincs beleszólása. Annyit tud megtenni csak, hogy minél több memóriát újrahasznál ( vagy a változók felszabadításával, vagy azonos jellegű változók újrahasznosításával ).
Üdv,
LuiseX

*Szerintem* azzal van a baj, hogy "nem standard malloc, főleg mert dinamikus a foglalás". (egyszerűsítés és kiemelés tőlem)

A standard malloc pontosan a dinamikus foglalásra van. Ha statikus foglalást akarunk, akkor azt írjuk, hogy


#define NUM_OF_INTS 1000
int a[ NUM_OF_INTS ];

ha pedig dinamikusat, akkor valami ilyesmit


#define NUM_OF_INTS 1000
int *aPtr = NULL;
aPtr = malloc( NUM_OF_INTS * sizeof( int ) );
if ( aPtr == NULL ) {
perror( "Allocation of ints failed" );
exit( errno );
}

(És persze normális esetben valahol majd lesz egy free( aPtr ) is.)

Bízom benne, hogy ez nem volt neked újdonság, de a mondat nagyon rosszul lett megfogalmazva.
=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?

Szia,
Nem, nem volt újdonság, csak reggel volt még emberi nyelven is beszélni :D
Amire utalni akartam mindössze, hogy a Perl memory handlere greedy megközelítéssel addig tart magánál mindent, amíg nem szégyelli magát.
Ez leginkább a működési elvéből ered:futásidőben interpretált nyelv, 0 előfordítással, alapvetően mindent dinamikusan betöltve, ami csak létezik. Ez pedig memória igényes folyamat, és feltehetőleg mallocon és reallocon próbál spórolni, amennyit csak lehet (A forrást nem néztem meg még).
De irónia, hogy a JVM és a C# is hasonló elven kezeli a memóriát,de azok memória igényét ellenben kevesen firtatják, mivel ott van legenda a GC működéséről :)
De köszönöm szépen a korrekciót mind neked ,mind Wachagnak :)
Üdv,
LuiseX

De irónia, hogy a JVM és a C# is hasonló elven kezeli a memóriát,de azok memória igényét ellenben kevesen firtatják

A JVM-nél vannak paraméterek, hogy mennyit egyen, mennyit ehet. Utána a GC takarít. Ha még így sincs elég memória, akkor out of memory exception formájában megáll az egész kóceráj.

A perl addig nő, ameddig tud - ebből a szempontból a 32-bites perl azért jó, mert 4GB előtt meg fog állni - nagy eséllyel crash formájában (amikor legutoljára ilyennel volt tapasztalatom, az szépen crashelt, amikor a malloc() nullt adott vissza). A programok jelentős hányada amúgy nem tud mit kezdeni azzal, ha még virtuális memóriát sem ad neki az OS, jobb esetben abort lesz belőle, rosszabb esetben simán használják a null-pointert, és azért állnak meg.

"A JVM-nél vannak paraméterek, hogy mennyit egyen, mennyit ehet. Utána a GC takarít. Ha még így sincs elég memória, akkor out of memory exception formájában megáll az egész kóceráj.

A perl addig nő, ameddig tud"

A javás kódodnak a virtuális gép által adhatod meg, hogy meddig terjeszkedhet, ha az alapértelmezet korlátokat túl liberálisnak tartod.
A perlös kódodnak meg az ulimiten keresztül.

Nem érzek én akkora különbséget itt.

Biztosan létezik az a feladat és környezet, amelyben fontos/jellemző, hogy:
- perl (v5) legyen a nyelv,
- a memóriafoglalás fluktuál,
- az inaktívvá vált memóriát vissza kell adni az oprendszernek, és inkább újrakérni tőle később,
- valamilyen kondíció alapján még azt is meg kell szabni, hogy mennyi lehet a pillanatnyilag használható memória (ez a legérhetetlenebb kitétel, a vm-varázslások korában, de legyen!),
bár én még nem találkoztam ilyennel.

Ha pont ilyenbe futnék bele, a visszaadás/limitváltozás igényére simán letárolnám az aktuális állapotot (ha van memória, csak a perlt kell szopatni a használat tiltásával, akkor redis, különben diszk), és ujraexecelnék a korrigált ulimittel.
Közben azért cöccögnék és mutatnám a véleményem nemzetközi jelét a halántékomra helyezett mutatóujjal.

Szia,
Nem rossz, igazából, csak tudni kell, mire való a nyelv és a perl bináris :) Mivel a nyelv 100% dinamikára akar építeni, ebből ered, hogy máshol kell spórolnia. Előfordítási/interpretálási fázisban szimplán nem tud optimalizálni, így az erőforrás menedzsmenttel csal: Greedy megközelítéssel amit lehet, megtart, amíg "nem kérik vissza tőle" :)
Üdv,
LuiseX

"Standard malloc() használata esetén kb. kizárt, hogy a perl bármi memóriát visszaadjon az OS-nek UNIX-okon."

Ez már régóta nincs így, sok malloc implementáció visszaadja a nagyobb méretű lapokat.

Tessék, mutatok valódi UNIX-os példát :)
http://h20566.www2.hpe.com/hpsc/doc/public/display?docId=emr_na-c032204…

Csak azt nem értem, hogy mit vártál, hogyan kellene ennek a kódnak szerinted viselkednie?

Létre hozol egy tömböt, majd dinamikusan bővíted, még szép, hogy így működik...

Nyilván az is igaz, hogy ha megmondtad volna milyen hosszú a tömb, akkor is növekedne a memória használat, hiszen random számokat teszel a tömbbe. Ha a Perl -ben meg lehetne mondani, hogy létrehozok egy 10000 elemet tartalmazó tömböt, amely 4 byte -os pozitív egész számokat tartalmaz, akkor pontosan számítható lenne, hogy ez 40000 byte, de a Perl egy nem típusos nyelv.

Kis olvasni való: http://perldoc.perl.org/perlfaq3.html#How-can-I-make-my-Perl-program-ta… http://perldoc.perl.org/perlapi.html#Memory-Management

----
올드보이

Helló Kayapo!
Az @a nevű tömbbe beleírom a 100k adatot. Ezzel nincs is probléma, ez befejeződik. A második részben ennek a tömbnek a tartalmából válogatok le adatot, amit a @res nevű tömbbe gyűjtök (statisztika).
A @res tartalma minden ciklusban el van dobva, majd újra meg újra felűl van írva. Na ekkor fogy a memória, de veszett módon. Ez a problémám, mert sok az adat, és az OS először elkezd swap-elni, majd szétrúgja az egyéb task-okat, aminek a vége már szerintem számodra is ismert.
Üdv,
vfero

Szia,
A kérdés az, hogy tényleg eldobatod a tömböt, vagy csak azt a refet dobatod el, ami a tömb leíróra mutat?
Ha a tömböt és az elemeit _is_ el akarod dobatni, akkor érd el, hogy kifusson a scope-ból. A legegyszerűbb megoldás, hogy a my @res sort berakod a foreach alá.
Üdv,
LuiseX

+1,
a @res = () nem felszabadítás, hanem újra assignolja csak a tömböt ( tehát, az elemek refcountja megmarad! )
Perlben a felszabadítás csak és kízárólag a scope végén zajlik (ha még van hivatkozás az elemekre, tehát nem lett a tömb újra assignolva), vagy, ha egzaktul minden elemhez undefet rendelsz.
Scope pl. a { és a } jel között van.

Üdv,
LuiseX

Szia,
Akkor kezdem nem érteni, hogy pontosan mit csinálsz...
Ha a leírt kódot használod , ÉS nincs sehol reassign a @res-re, csak undefeled amit nem kell és az elemeivel dolgozol, @res mindig felüíródik.
Amennyiben a checkLimitnek átadott \@res-ed csinál egyetlen egy @{$res}= műveletet, akkor már újraproblémába kerülhetünk, de akkor is $#res max. értékének kell lennie a memória foglalásnak.
A perl mindenképp legfolalja majd a @res maximiális méretű helyét , és addig nem fogja elengedni, amíg "az OS nem piszkálja, hogy kellene". De ennél többet nem foglalhat le így már.
És, ez -mármint, az általam taglalt - működés nem leakelés, hanem a perl alapértelmezett működési elve.
Üdv,
LuiseX

Helló LuiseX!

A problémám az, hogy a @res értékét újra, és újra felül írom, de valószínűleg nem felül írja, hanem új területet foglal minden ciklusban. Így képes hízni, hatalmasra.
Mindenféleképp próbáltam mát átszervezni, tehát hogy a függvény hívást is kiszedtem, egyszer foglalom, minden iterációnál foglalom, felszabadítom undef-el minden iterációban, stb, de nem tudom a folyamatos memória éhségét megállítani.
Van ~500M-nyi log, amit ~3G-nyi memóriába parse-ol az eredeti script, amin ~1500-2000 iterációt kellene végrehajtani. A 200. körben már 35G-nyi memóriát zabál.
Ezt szeretném kikerülni, mert rendkívül lelassítja a kiértékelést.
Kösz a tippeket előre is!
Üdv,
vfero

Szia,
A gond az, hogy az itt megadott kódnak már nem lenne szabad "memleakelnie".
Az egyetlen dolog amit még meg tudsz tenni innentől, az az, hogy végigiterálod a tömböd elemeit, és minden elemet undefre teszel. De ez írtó költséges cpu-ra nézve. Ugyanezt kellene megtennie a Scope végének, csak kicsit gyorsabban (Scope-ról bővebben: http://www.perlmonks.org/?node_id=66677 ).
A perl lelkében a változó kezelés kicsit kacifántos, és változók helyett inkább (cpp-s) refekben érdemes gondolkozni, ha memóriát számolsz. A gond az lehet még, hogy a tömbök valójában ref halmazok, nem pedig konkrét tömbök.
Ha két tárolt adat értéke "ránézésre azonos" (pl. @new_res[200]= @res[150] ), a perl csal, és ugyanarra a memória területre mutat velük, és növeli a címzett memóriaterület refcountját. Amennyiben (csak) az egyik változna, átköltözik egy új memóriaterületre az új értékkel, és az előző helyen csökken a refcount. Ez a szép és könnyed megoldás.
Ellenben, ha pl. egy tömböt kényelmesen átadsz \@res formában, és mivel nem szereted hosszan írni a @{$res} formát, írsz egy @internal_res=@{$res_param} parancsot, akkor az eredeti @res-re lesz egy új refed (és egyel növekszik a refcountja), amíg azt nem változtatod.
De! Ha ez fennáll is, akkor is max. max(2*@#res) méretű lehet a memória foglalásod (mivel a tömb újra létrehozásánál az eredeti terület fennmarad, ha egy függvény scope-jában változónak adtad értékül az egészet. Ez egy tényleges perl betegség, sajnos by design).
Ennél semmiképp sem lehetne több. Kivéve, ha valahol sikerül megszaporítanod valamilyen perverz módon, például "idegen", meg nem szűnő scope-okban (függvények, még létező osztályok, closure-k amik még nem lettek felszabadítva - pl. tart az ő scopejuk ) referenciát oldasz fel @myres=@{$res_param} kényelmesítéssel.
De ekkor sem növekedhetne lineárisan a memóriafoglalásod, maximális értéke megegyezne a @res maximális méretének és és az ilyen feloldások számának szorzatával, konstans.
Ezt mindössze csak azért fejtettem ki számodra, hogy ha megosztani nem is tudnád a kódot (ahogy lentebb kérték), de legyen sejtésed, hogy hol lehet egyáltalán hiba.
Üdv,
LuiseX

En inkabb egy pmap-ra lennek kivancsi, hogy lassak mindent. Csomo anon meg stck lehet.

Amugy meg mi van ha megprobalsz ket allomanyt osszediffelni amiknek a merete egyenkent a memoriad fele? Szerintem fel fog szabadulni a perl processzbol, hogy a diffet meg tudja csinalni. Igaz ez a diff szepen kitisztit minden memory cache-t igy kicsit be fog lassulni a gepeden minden. :D


0000000000400000      8K r-x-- perl
0000000000601000      4K r---- perl
0000000000602000      4K rw--- perl
000000000169b000 20548276K rw---   [ anon ]
00007fb63bd13000   9652K rw---   [ anon ]
00007fb63c680000  10612K rw---   [ anon ]
00007fb63d6fd000     28K r-x-- ReadKey.so
00007fb63d704000   2044K ----- ReadKey.so
00007fb63d903000      4K r---- ReadKey.so
00007fb63d904000      4K rw--- ReadKey.so
00007fb63d905000     72K r-x-- MoreUtils.so
00007fb63d917000   2048K ----- MoreUtils.so
00007fb63db17000      4K r---- MoreUtils.so
00007fb63db18000      4K rw--- MoreUtils.so
00007fb63db19000     12K r-x-- Util.so
00007fb63db1c000   2044K ----- Util.so
00007fb63dd1b000      4K r---- Util.so
00007fb63dd1c000      4K rw--- Util.so
00007fb63dd1d000     28K r-x-- Streamer.so
00007fb63dd24000   2044K ----- Streamer.so
00007fb63df23000      4K r---- Streamer.so
00007fb63df24000      4K rw--- Streamer.so
00007fb63df25000     16K r-x-- PadWalker.so
00007fb63df29000   2044K ----- PadWalker.so
00007fb63e128000      4K r---- PadWalker.so
00007fb63e129000      4K rw--- PadWalker.so
00007fb63e12a000     12K r-x-- Fcntl.so
00007fb63e12d000   2048K ----- Fcntl.so
00007fb63e32d000      4K r---- Fcntl.so
00007fb63e32e000      4K rw--- Fcntl.so
00007fb63e32f000     32K r-x-- Dumper.so
00007fb63e337000   2044K ----- Dumper.so
00007fb63e536000      4K r---- Dumper.so
00007fb63e537000      4K rw--- Dumper.so
00007fb63e538000     12K r-x-- Utils.so
00007fb63e53b000   2044K ----- Utils.so
00007fb63e73a000      4K r---- Utils.so
00007fb63e73b000      4K rw--- Utils.so
00007fb63e73c000     20K r-x-- Util.so
00007fb63e741000   2048K ----- Util.so
00007fb63e941000      4K r---- Util.so
00007fb63e942000      4K rw--- Util.so
00007fb63e943000    328K r-x-- re.so
00007fb63e995000   2044K ----- re.so
00007fb63eb94000      4K r---- re.so
00007fb63eb95000      4K rw--- re.so
00007fb63eb96000     60K r-x-- B.so
00007fb63eba5000   2048K ----- B.so
00007fb63eda5000      8K r---- B.so
00007fb63eda7000      4K rw--- B.so
00007fb63eda8000      8K r-x-- NamedCapture.so
00007fb63edaa000   2044K ----- NamedCapture.so
00007fb63efa9000      4K r---- NamedCapture.so
00007fb63efaa000      4K rw--- NamedCapture.so
00007fb63efab000     16K r-x-- IO.so
00007fb63efaf000   2044K ----- IO.so
00007fb63f1ae000      4K r---- IO.so
00007fb63f1af000      4K rw--- IO.so
00007fb63f1b0000     12K r-x-- Call.so
00007fb63f1b3000   2044K ----- Call.so
00007fb63f3b2000      4K r---- Call.so
00007fb63f3b3000      4K rw--- Call.so
00007fb63f3b4000   4352K r---- locale-archive
00007fb63f7f4000     36K r-x-- libcrypt-2.19.so
00007fb63f7fd000   2048K ----- libcrypt-2.19.so
00007fb63f9fd000      4K r---- libcrypt-2.19.so
00007fb63f9fe000      4K rw--- libcrypt-2.19.so
00007fb63f9ff000    184K rw---   [ anon ]
00007fb63fa2d000    100K r-x-- libpthread-2.19.so
00007fb63fa46000   2044K ----- libpthread-2.19.so
00007fb63fc45000      4K r---- libpthread-2.19.so
00007fb63fc46000      4K rw--- libpthread-2.19.so
00007fb63fc47000     16K rw---   [ anon ]
00007fb63fc4b000   1044K r-x-- libm-2.19.so
00007fb63fd50000   2044K ----- libm-2.19.so
00007fb63ff4f000      4K r---- libm-2.19.so
00007fb63ff50000      4K rw--- libm-2.19.so
00007fb63ff51000     12K r-x-- libdl-2.19.so
00007fb63ff54000   2044K ----- libdl-2.19.so
00007fb640153000      4K r---- libdl-2.19.so
00007fb640154000      4K rw--- libdl-2.19.so
00007fb640155000   1768K r-x-- libc-2.19.so
00007fb64030f000   2048K ----- libc-2.19.so
00007fb64050f000     16K r---- libc-2.19.so
00007fb640513000      8K rw--- libc-2.19.so
00007fb640515000     20K rw---   [ anon ]
00007fb64051a000   1536K r-x-- libperl.so.5.18.2
00007fb64069a000   2044K ----- libperl.so.5.18.2
00007fb640899000     20K r---- libperl.so.5.18.2
00007fb64089e000     20K rw--- libperl.so.5.18.2
00007fb6408a3000    140K r-x-- ld-2.19.so
00007fb640a99000     20K rw---   [ anon ]
00007fb640ac3000      8K rw---   [ anon ]
00007fb640ac5000      4K r---- ld-2.19.so
00007fb640ac6000      4K rw--- ld-2.19.so
00007fb640ac7000      4K rw---   [ anon ]
00007ffd4d78d000    132K rw---   [ stack ]
00007ffd4d7d4000      8K r-x--   [ anon ]
ffffffffff600000      4K r-x--   [ anon ]
 total         20619720K

"A @res tartalma minden ciklusban el van dobva, majd újra meg újra felűl van írva. Na ekkor fogy a memória, de veszett módon. Ez a problémám, mert sok az adat, és az OS először elkezd swap-elni, majd szétrúgja az egyéb task-okat, aminek a vége már szerintem számodra is ismert."
Üdv,
vfero

Na ott is van a 20G anon. Ha ez perl vagy modul memoria szivargas lenne, akkor az nem anon lenne, hanem valamelyik modul vagy binaris lenne akkora.
Ez egyszeruen egy rosszul megirt program. Te allokalod(allokaltatod) a memoriat de sosem szabaditod fel.

Erdekes lenne ciklusonkent megnezni, milyen szepen noveszted ezt az 'anon' reszt. :D

Szoval tuti nem az tortenik, amit irtal es amit szeretnel.

Itt valami disznóság van!

Ezért a kódodat kicsit kicsontoztam, meg megspékeltem azzal, hogy az elemzős részt többször lefuttatja: http://pastebin.com/GTyZ9vQv

Úgy viselkedik ahogy vártam: http://pastebin.com/1KtJKDgY szóval szerintem nincs itt memleak, csak lefoglalja a memóriát az interpreter. Azon lehetne vitatkozni, hogy ezt a foglalást, hogyan lehet csökkenteni, de az egy más tészta

Esetleg le lehetne futtatni valami elmerogyant hosszúságú tömbön, pl.: 100.000.000.000 elemmel, hogy akkor mi a helyzet, de szerintem e pillanatban nincs itt hiba!

----
올드보이

Kösz a segítséget!
Értem a gondolat menetedet, de sajnos nem fut normálisan, mert a 9. sorban pointerrel hasonlítasz össze mindent.
Helyes szerintem:


push(@{$p_res}, $_) if $_ > ${$p_limit};

Ilyen futás alkalmával elsőre 4736k volt a tömbök mérete nálam, majd
11792k
14960k
...
14960k

Így már annyira nem finom, szerintem.
Üdv,
vf

Szia,
Izé, ne haragudj, hogy emiatt ide ugatok, de... a perlben nincs pointer (vagyis van, de ... az olyan dolog, amiről egy átlagos perl programozónak inkább nem szabad tudnia :) ), amire hivatkozol, az a default variable ($_), kényelmi funkció csak :)
Kis magyarázat rá, ahol kifejtik mit is jelent: http://perlmaven.com/the-default-variable-of-perl
Zavarásképpen a $_ valójában a @_ első eleme :)
Üdv,
LuiseX

Megtennéd, hogy bemásolod azt a kódot, amivel valójában bajod van?

Letakarítottam róla az antipatterneket és betettem egy ciklusba, hogy kiderüljön, tényleg növekszik-e a memóriafoglalás:

http://pastebin.com/AUfqZe00

Nálam az első két iteráció után nem változik semmi.

Ne vedd sértésnek, de a kódstílus és néhány szintaktikai ügyetlenkedés ( %res->{"no"} ) alapján úgy tűnik, hogy nem vagy nagyon gyakorlott perlben, így valószínű, hogy miközben megpróbáltad anonimizálni a kódot, épp azt a részt távolítottad el, amely a problémát okozza.

Na végre sikerült előidéznem a memleak -et: http://pastebin.com/61JqhrCv

A kimenet így néz ki:
* http://pastebin.com/ktEH8D3a (itt nincs a kódban az undef @res; sor)
* http://pastebin.com/ZhYuzGYA (itt benn van a kódban az undef)

És az a gyanúm, hogy az interpreter csak akkor szabadítja fel a @res memóriáját, amikor a my @res lefut, hiszen akkor kutya kötelessége felszabadítania, hiszen abban a kontextusban az egy lokális változó. Érdekes a probléma, a megoldás még érdekesebb lesz. Ha sikerült találnom valamit megint írok.

Szerk. 1:

A megoldás persze Kolumbusz tojása: http://pastebin.com/yEab595q

Hiszen nem csak a @res fogyaszt memóriát és ha hagyjuk akkor az interpreter igyekszik mindaddig megtartani amíg csak lehet. Az első ciklus után a $c -től, valamint a &checkLimit() végén a subrutin változóitól sem szabadultunk meg. ezek természetesen tovább csökkentik a memória fogyasztást.

Szerk. 2:
Eddig: http://pastebin.com/RYWiDr1C jutottam és nem értem, ehhez egy programozásban jártasabb ember kell. Az tuti, hogy memleak, de hogy hol szivárog arról elképzelésem sincs. Ez így 4,5MB memória növekedés. Ha ez problémás, azt javaslom, keress más nyelvet ne szopasd magad Perl -el

----
올드보이

Szia,
Egyszer már megtettem, tehát, csak linkelném: http://hup.hu/node/148760#comment-2009029 és http://hup.hu/node/148760#comment-2008705
A perl így működik, leírtam mekkora lehet a max. memória foglalás :)
A perl belsejében vannak bizonyos trükkök, hogy spóroljon CPU-n ( kontextus létrehozáson) és memórián (refcount témakör), és ezekről a leírás a fentebbi linkek alatt megtalálható nagyjából, vagy a korábbi hozzászólásaimban.
Mint ott is leírtam, ha a jelzett mértékű memória használat van, undefelni lehet, és tudsz nyerni egy kicsit. Ellenben, sajnos, ez az alapértelmezett. A perl nem 4gb adat kezelésre van, hanem gyors szövegparseolásra. El kell fogadni a limitációit :)
Ha megbocsájtasz, nem ismételgetném magamat, vagy fejtegetném tovább a témakört már :)
Üdv,
LuiseX

Nem, nem sikerült előidézned. Ha jobban megnézed a számaidat, láthatod, hogy a második kör után nem növekszik a foglalás. A kérdező azt állítja, hogy nála folyamatosan növekedett a memóriahasználat és a végére gigabájtokat evett meg.

A perl pontosan annyit foglal itt, amennyit kell és nem többet.

Amúgy... ha tényleg csak ennyi lenne a feladat, akkor még az a checkLimit függvény sem kellene, elég lenne egy egyszerű grep. De mivel itt egy XY problémával állunk szemben (a kérdező valójában X-et szeretne, de Y-t kérdez), nincs esélyünk érdemben segíteni.

Biztos hogy NEM a perl a hibas, ami a pmap kimeneten is latszott. Az algoritmus a hibas. Valoszinuleg mas modon kellene az egeszhez hozzaallni, uj modszert kitalalni a feldolgozasra.

Arrol van szo, hogy olyan algoritmust hasznal, ami folyamatosan eszi a memoriat - hangsulyozom, hogy nem a Perl eszi, hanem az o kodja!

Amugy en abban sem vagyok biztos, hogy a @res tartalma none folyton es folyton a memoriaban. Lehet a checklimiten belul no valahol. Valami debugger kellene ide.

Sziasztok,
Teljesen egyetértek veletek. De amíg ennyire memória zabáló mechanizmust használ, addig jó lenne megállapítani, hogy tényleg növekszik a fogyasztás, vagy valójában csak az elvárható mennyiségre "gyarapszik".
Amíg ezt nem becsli meg, addig nehéz lesz meglátni azt, amit hibának mond.
Pont ezért írtam le N-szer, hogy hogy kell a perlben az ilyen memória igényeket számolni.
Az általa megadott kódban én sem látok tényleges leaket, ez az elvárható memória fogyasztás attól, amit leírt...
Üdv,
LuiseX

Felületes szemlélőnek úgy tűnhet, hogy a kód a szar, de nem. Ha ebbe http://pastebin.com/RYWiDr1C a kódba a 41 -edik sorba is beteszel egy memstatot, akkor egyértelműen kiderül, hogy gond van az interpreterrel.

Meg lehetne nézni az egész futást strace -el, több derülne ki abból, hogy mi is foglalja le a memóriát és, hogy történik-e memória felszabadítás

----
올드보이

Szia,
Most nem áll módomban lefuttatni, sajnos. De mire gondolsz?
Arra, hogy a függvény után nem szabadul fel a memória? Ez a perl alapműködése.
Ajánlom figyelmedbe a "my $var if undef;" változó deklarálást. Párszor már leírtam ezt is :)
Vagy konkrétan arra gondolsz, hogy egyre több és több memóriát eszik iterációnként, lineáris jellegű növekedést mutatva?
Üdv,
LuiseX
U.i: Belső memória ellenőrzésre ez hasznos lehet http://search.cpan.org/~doneill/Memory-Usage-0.201/lib/Memory/Usage.pm :)
Szerk: Bocsi, elírtam elsőre :)

Arra gondolok, hogy a foreach $limit (...) rész után a memória használat növekménye több, minta az azután következő undef -ek utáni csökkenés.

Sőt ha végig nézzük, hogy az egyes logikai egységek előtt és után mennyi a memória használat azt látjuk, arra következtetek, hogy azok az objektumok amiket a perlnek - elvben - meg kellene szüntetnie (ciklusok) nem szűnnek meg.

----
올드보이

Szia,
Először is, a perl nem fogja vissza adni az OS-nek a memóriát, amíg nem gondolja úgy, hogy az OS-nek jobban kell. Az undef-el csak clear-nek flageli, és a belső memória kezelő újrakiosztja majd.
Ezáltal, a memória foglalásnak a maximuma meg fog egyezni azzal, ami a legnagyobb memória használat idején volt, kb. a teljes futásidőre ( ritkán sikerül megennie a perlnek az OS elől a memóriát).
Azzal, hogy @res=(); -t hívtok, még nem garantáljátok a clear-nek jelölését a res elemeinek.
Arra csak és kizárólag az ad lehetőséget, ha végig pörgeted az összes elemét a @res-nek, és undefre állítod explicit. Különben, ha valahol (például egy függvény tárolt contextusában) van referencia a tömb egyes elemeire, nem fogja felszabadítani feltétlenül. Ez utóbbi esetben lehet memleak szerű viselkedés, de erre utaló jeleket nem láttam a kódban :)
Viszont, a perl _kívülről_ nézve memória intenzív, de valójában csak önző módon foglal : amit elkapott, ahhoz ragaszkodik, amíg nem követelik tőle. Addig nem fog free-t hívni a memória területekre, amíg nem elkerülhetetlen, ezáltal egy külső programból (pl. memstat) azt lehet hinni, hogy memleakel.
De amit linkeltem modul rámutat(hat), hogy valójában leakel-e...
Üdv,
LuiseX

Rossz dologra vetodol. A nagy meretu virtualis memoriafoglalas nem feltetlen problemas.

http://stackoverflow.com/questions/7880784/what-is-rss-and-vsz-in-linux…

Lefuttatam en is, es erre ranezve:
5052k( 0k): /usr/lib/locale/locale-archive 10766

A proc smaps alatt ezek tartoznak hozza:
7efc8c21a000-7efc8c709000 r--p 00000000 fc:00 6433129 /usr/lib/locale/locale-archive
Size: 5052 kB
Rss: 652 kB
Pss: 370 kB
Shared_Clean: 484 kB
Shared_Dirty: 0 kB
Private_Clean: 168 kB
Private_Dirty: 0 kB
Referenced: 652 kB
Anonymous: 0 kB

Latszik hogy bar nagy meretu, abbol keveset hasznal, es azt sem "piszkolta ossze".

http://unix.stackexchange.com/questions/33381/getting-information-about…