Speicherbedarf eines Prozesses

Jan 'RedBully' Seiffert redbully at cc.hs-owl.de
Mon Apr 26 21:23:49 CEST 2010


Sascha Effert schrieb:
> Am Freitag, den 23.04.2010, 17:47 +0200 schrieb Jan 'RedBully' Seiffert:
[snip]
>> Ein Beispiel um zu verdeutlichen was ich meine:
>> Der Stack eines Programms (oder threads) ist erstmal ein mmap von Anon speicher,
>> dahinter die sogenannte guard page. Wenn dein Programm jetzt mehr stack braucht,
>> laeuft es in die guard page, der stack waechst nach unten. Mehr Speicherseiten
>> werden Stueck fuer Stueck in den Stack gefaultet. Das ist soweit erstmal alles fit.
>> Wo man sich jetzt ins Knie schiessen kann: Beim Programmstart brauchst du aus
>> irgendeinem Grund viel Stack (Grosse Config/Cache Datei wird in Puffer auf Stack
>> geladen, irgendein rekursiver Algo bereitet den run vor), Dein Stack waechst aus
>> diesem "once-off" Grund auf enorme Groessen (Sagen wir 2 MB), der restliche Lauf
>> des Programms braucht den Stack aber nicht mehr so gross (oft irgendwas im
>> Bereich < 64k), denoch hast du den Speicher "ge-captured".
> 
> Also, zunächst: Hast Du gerade 2 MB als enorme Speichermenge bezeichnet?

Ja. Wieso nicht?
Sicher, es kommt drauf an wie das Verhaeltniss ist zum Rest des Programms.

> Im Moment liegt mein Prozess bei fröhlich 62 GB RSS, 64 GB Virt (hab den
> Swap noch laufen). 
> 

OK, bei 65 GB ist das pille-palle.
Aber selbst bei 100MB sind das 2% und 2MB die sich vielleicht besser fuer was
anderes nutzen lassen. (low hanging fruit, wenn dein Profile fuer fast jede
Nutzung 0.1% anzeigt (alles ist gleich "boese"), dann ist so ein 2% Ding schon
nett was, an dem man saegen kann).

Ausserdem hatte ich extra auf Stack hingewiesen weil:
Der default stack fuer pthreads unter Linux ist z.B. 1MB. Zwar erstmal nur VSZ,
aber denoch. Und jetzt mach mal die Nummer N an Threads gross...
Da bin ich mit meinem Serverprozess reingerannt. Da FreeBSD das normalerweise
auf 64k stellt, hab ich das dann einfach auch unter Linux umgestellt
(pthread_attr_setstacksize()), um das besser im Auge behalten zu koennen.

> Ich habe das Programm so aufgebaut, dass es immer recht große Blöcke an
> Speicher sind, die gleichzeit allokiert/deallokiert werden. Daher dürfte
> ich zumindest mit dem Verschnitt des pages keinen größeren Probleme
> haben.
> 

Hmmm, ja, dann hast du einerseits wenig overhaed, aber andereseits aendert das
nichts am Grundproblem:
Wenn du eben einen "dummen" algo hast (alloc, alloc, alloc ... alloc ergebniss,
gib die ersten wieder frei), dann haelt ein Stueck hinten viele Stuecke "in der
mitte" fest. (Die koennen dann zwar wieder fuer irgendwas benutzt werden, aber
es kommt auf den Ablauf deines Programmes an fuer was, und ob das die
Fragmentation nicht noch schlimmer macht).
Ist so ein bischen das elend an moderner Programmiererei:
Jo, packt ich das erstmal alles in ein std:vector (oder insert
$SYNTAKTISCHEN_ZUCKER here), fuehrt schnell zu Ergebnissen (das proklamiert
"wichtigste" heutzutage), aber hat eben Nebenwirkungen. "Every abstraction is
leaky"...
Ein Blick fuer das was im Hintergrund passiert und deine N's ist immer hilfreich ;)

Grosse Stuecke (wie gross genau?) werden erst durch mmaps bedient (koennen
einzeln freigegeben werden), der glibc Allokator "lernt" dann aber, das der
durchschnitt grosse allokationen sind, so das er irgendwann anfaengt, die auch
vom Heap zu holen.
(Der Grund ist, das der Heap im allgemeinen schneller ist und das ein Prozess
nur eine Begrenzte Menge an mappings aufsetzen kann, das kann man zwar
hochsetzen, aber...)

Ich seh das sehr gut bei meinem Serverprozess. Ich hab da sehr aggresiv
allokationen optimiert, so dass was regelmaessig alloziert wird entweder random
unter 300 Byte ist oder 128kb Bitmaps. Die ersten Bitmaps werden noch
ge-mmap-ed, irgendwann schaltet dann die glibc auf den heap um.

> Ach ja, für alle denen noch klar war, wie schlimm XML mit DOM ist: Wenn
> ich mit der libxerces-c eine 4 GB XML Datei als DOM lade, dann braucht
> das ca. 40 GB RAM... (Ich war jung und hatte den Speicher...) Vielleicht
> werfe ich den XML-Kram noch raus und ersetze ihn durch irgendwas
> sinnvolles.
> 

Ja, XML....
Wenn du mal schaust (Achtung, ich bin da nicht so drin...), es gibt bei der XML
verarbeitung ja auch streamfoermige APIs, wenn du die irgendwie benutzen kannst?

(an der libxml2: Die ganze xmlReader API, z.B. xmlReaderForMemory(),
xmlTextReaderRead(), mal ein bloedes Beispiel:

for(ret = xmlTextReaderRead(reader); 1 == ret; ret = xmlTextReaderRead(reader))
{
	if(xmlTextReaderDepth(reader) > 40)
		break; /* flood schutz */
	while(xmlTextReaderMoveToNextAttribute(reader) > 0)
	{
		const xmlChar *attr_val = xmlTextReaderConstValue(reader);
		/* tu irgendwas mit attr_val */
	}
}

Konnt ich mal so gebrauchen, hab ich dann aber rausgeschmissen, sch... XML
bloat, der kram war sowieso nur IMHO xml-like (Wohlgeformt? Wer ist tot?), nen
memchr tat's auch ;)
)

> Nur um sicher zu gehen: sehe ich es richtig, dass ich den SWAP wirklich
> abstellen muss, damit der Prozess ihn nicht verwendet?

Jein.
Solange er da ist kann er verwendet werden, wird meist nur nicht (solange genug
"frei" ist und du nicht zuviel IO machst so das ein Hunger nach Cache und
Buffern entsteht, siehe swappiness unten).
Mit anderen Worten: solange er nicht benutzt wird, ist alles gut, wenn er
benutzt wird, musst du eh nen swappoff machen, also kannst du ihn gleich aus
machen...

> Oder gibt es irgendeine Möglichkeit dem Betriebssystem zu sagen, dass bestimmter
> Speicher (oder Speicher von bestimmten Prozessen) nicht geswapt werden
> darf?
> 

Du kannst allgemein /proc/sys/vm/swappiness runterstellen. Aber das ist nur ein
Hint, kein Befehl.
Je kleiner der wert ist, desto unwahrscheinlicher ist es das der Kernel ein
Programm rausswapt. Er recyceld dann seinen Cache aggressiver, was aber im
normalen Betrieb nicht immer unbedingt das beste ist.

Dann kannst du mit mlock speicher "festpinnen".
ABER:
Als normaler user nur 64k, und das ist gut so!
Nur root kann mehr Speicher fest pinnen.

Dann gibt es noch mlockall (braucht auch "erweiterte" Rechte), mit dem flag
kannst du dann einstellen was gepinnt werden soll. Z.B. am Anfang des Programms
ein mlockall(MCL_FUTURE).

Aber Achtung: Mit dem pinnen kannst du die VM echt in Bedraengniss bringen,
besonders wenn du das fuer solche mem eater benutzt.
Eigentlich ist das fur RT oder Crypto gedacht, wo du ein KLEINES RT Stueck oder
Keys & Cryptocode deines Programms festpinnst.

> tschau
> 
> Sascha
> 
> 
Gruss
	Jan

-- 
John encountered the following Zen-like line in his generated XML:
	<>There is no phenotype</>
He was enlightened.



More information about the Linux mailing list