Wirklich 100% nachvollziehbar ist das nicht. Du verwendest vermutlich Mono? Mono hat (im Gegensatz zu LSO) als VM tatsächlich eine Garbage Collection. Wann der Collector tatsächlich läuft weiß ich leider nicht, das wissen wohl nur ein paar Lindens genau ;-)
Mit Mono-Scripts hat das aber direkt nichts zu tun:So sind im Bytecode der Scripte ziemlich viele Stop-Codes einkompiliert, d.h. die Scripte machen nach fast jeder Funktion und jedem Event usw. einen kleinen Stop. So dass sie zu diesem Zeitpunkt "eingefroren", mit der atuellen Variablen-Belegung usw. abgespeichert und z.B. aus der VM genommen werden können um so auf dem Asset-Server zu landen (wenn man ein Script einpackt) oder um auf einem anderen Simulator in dir VM dort entpackt zu werden und dort an der Stelle nach dem Stop weiter zu laufen (bei einem TP oder beim Auspacken aus dem Inventory etwa). Und an jedem dieser Stops wird in Mono auch die Größe des vom Script belegten Speichers geprüft. Wie viel Speicher das Script zwischen den Stops belegt ist dabei egal (das können auch > 65kB sein) - aber beim Stop darf ein Script dann lediglich 64kB groß sein - sonst wird es von der VM einfach kurzerhand nicht weiter ausgeführt und die VM spuckt die Fehlermeldung "Stack/Heap Collision" aus - auch wenn es eigentlich gar keiner ist. Das ist lediglich die gleiche Meldung, die bei LSO-Scripts kam, wenn deren 16KB-Block zu voll war. Und an diesen Stops kann natürlich auch der Garbage Collector laufen. (Muss aber nicht).
llGetFreeMemory spuckt darüber hinaus auch lediglich aus wie viel Speicher
vor der nächsten Garbage Collection noch frei ist, d.h. wie viel Speicher noch belegt werden könnte, bis das 64kB Soft Limit erreicht wurde. Da aber möglicherweise direkt im Anschluss tatsächlich der Garbage Collector laufen könnte kann es durchaus sein, dass eigentlich noch wesentlich mehr Speicher frei ist. Für Mono ist diese Funktion daher eigentlich unbrauchbar. Und in deinem Fall scheint es wohl so auszusehen als ob zufällig direkt davor der Garbage Collector gelaufen ist. Da das aber nicht gezwungenermaßen gleich passieren muss (in Mono ist der Garbage Collector je nach Version u.Umständen bisschen komplizierter...) ist ein Aufruf llGetFreeMemory verständlicherweise alles andere als eine saubere Lösung für dein Problem.
Du solltest also eher über llGetUsedMemory den momentan vom Script tatsächlich belegten Speicher zu kritischen Zeitpunkten abfragen oder aber über llScriptProfiler und llGetSPMaxMemory einmal ein Memory Profiling durchführen. Damit läuft das Script während des Profilings (also solange es nicht resettet wurde, die Region gewechselt hat, derezzt wurde usw.) zwar 100 mal langsamer - aber du kriegst damit raus wie viel Speicher dein Script während der bisherigen Laufzeit maximal belegt hat.
Alternativ kann man notfalls auch mit einem Stück Papier, einem Bleistift und einem Taschenrechner manuell berechnen wie viel Speicher dein Script zu welchem Zeitpunkt mindestens belegt. Siehe
http://wiki.secondlife.com/wiki/LSL_Script_Memory