Ko skaitiklis nemato
Ta pati komanda spausdina ir antrą dalį:
keeping only the LAST item of a 100000-item queue:
q = q[1:] (header points into array) 7034 KB still on the heap
copied the survivor out 0 KB still on the heap
Iš 100 000 įrašų eilės liko vienas. Su q = q[1:] atmintyje tebėra
7 megabaitai.
Kodėl
q[1:] nesukuria naujo masyvo. Jis grąžina antraštę, kuri rodo į tą patį
masyvą, tik viena vieta toliau. Kai išimi 99 999 įrašus, lieka vieno elemento
slice — bet jo rodyklė vis dar nurodo į vidurį šimtatūkstantinio masyvo.
Šiukšlių surinkėjas negali laisvinti masyvo dalimis. Masyvas arba pasiekiamas, arba ne. Vienas gyvas elementas išlaiko visą masyvą.
Todėl copied the survivor out rodo nulį: nukopijavus tą vieną įrašą į naują
slice, senas masyvas tampa nepasiekiamas ir dingsta.
Ką iš tikrųjų reiškia šis rezultatas
Pirmoje pamokoje pasakėm: skaičiuok veiksmus, o ne sekundes, nes skaičius tikslus, determinuotas ir nepriklauso nuo technikos. Visa tai tiesa.
Bet skaitiklis matuoja laiką, ne atmintį, ir čia jis parodė nulį ties variantu, kuris nutekina septynis megabaitus.
Veiksmų skaičius — teisingas įrankis laikui. Atminčiai jis aklas.
Tai ne skaitiklio klaida. Tai jo ribos, ir dabar tu jas žinai. Nuo šiol, lygindamas struktūras, klausk abiejų klausimų.
Kodėl žiedinis buferis
Ring juda nulį elementų ir nieko neišlaiko: r.buf[r.head] = Item{}
išleidžia įrašą iš masyvo iškart, kai jis atiduotas. Vienas masyvas, fiksuoto
dydžio, niekada nejuda ir niekada neauga.
Kaina — reikia iš anksto žinoti dydį. Tai mainai, o ne pergalė.
Šitas nutekėjimas ateina ne tik iš eilių. Bet kada, kai iš didelio slice pasilieki
mažą gabalėlį — first := data[:10], tail := log[len(log)-5:] — laikai visą
masyvą. Jei gabalėlis gyvena ilgai, kopijuok jį: out := append([]Item(nil), data[:10]...).