Het materiaal van dit artikel is afkomstig van mijn .

In het verleden , ik had beloofd om de kwestie van de belastingsevaluatie op de ticker en manieren om overmatige rekenbelasting in de mediastreamer aan te pakken, te overwegen. Maar ik besloot dat het logischer zou zijn om de debugproblemen van de gepersonaliseerde filters die verband houden met gegevensverplaatsing eerst te belichten, en pas daarna de prestatiesoptimalisaties te bespreken.
Debuggen van gepersonaliseerde filters
Nadat we in het vorige artikel het mechanisme van gegevensverplaatsing in de mediastreamer hebben besproken, is het logisch om te praten over de verborgen gevaren daarvan. Een van de kenmerken van het principe 'data flow' is dat geheugenallocatie vanuit de heap plaatsvindt in de filters die zich aan de oorsprong van de gegevensstroom bevinden, terwijl geheugenontlasting met terugkeer naar de heap wordt uitgevoerd door filters die zich aan het einde van de stroom bevinden. Bovendien kan het creëren van nieuwe gegevens en hun vernietiging ergens in tussentijdse punten plaatsvinden. In het algemeen voert niet de filter die een gegevensblok heeft gemaakt, de geheugenontlasting uit.
Vanuit het perspectief van transparante geheugenbewaking zou het redelijk zijn dat de filter, bij het ontvangen van een inkomend blok, het onmiddellijk na verwerking vernietigt met geheugenontlasting en een nieuw gemaakt blok met uitvoergegevens aan de uitgang presenteert. In dit geval zou een geheugolekkage in de filter gemakkelijk te traceren zijn — als de analyzer een lek in de filter ontdekt, betekent dit dat de volgende filter de inkomende blokken niet op de juiste manier vernietigt en dat de fout daar ligt. Maar vanuit het perspectief van het handhaven van hoge prestaties is een dergelijke benadering van bediening van gegevensblokken niet productief — het leidt tot een groot aantal bewerkingen voor toewijzing/ontlasting van geheugen voor gegevensblokken zonder enige nuttige output.
Om deze reden gebruiken de mediastreamfilters, om de gegevensverwerking niet te vertragen, functies die lichte kopieën maken bij het kopiëren van berichten (waar we in het vorige artikel over hebben verteld). Deze functies creëren alleen een nieuwe instantie van de berichtkop, "vastgemaakt" aan een gegevensblok van het te kopiëren "oude" bericht. Dit resulteert in het feit dat twee koppen aan één gegevensblok zijn gekoppeld en de referentieteller in het gegevensblok wordt verhoogd. Maar het zal eruitzien als twee berichten. Het aantal berichten met zo'n "gedeeld" gegevensblok kan zelfs groter zijn; zo genereert de MS_TEE-filter bijvoorbeeld meteen een tiental van dergelijke lichte kopieën, verdeeld over zijn uitvoer. Bij correct functioneren van alle filters in de keten, zou deze referentieteller aan het einde van de keten nul moeten bereiken, en zal de geheugen vrijgavefunctie worden aangeroepen: ms_free(). Als deze aanroep niet plaatsvindt, betekent dat dat dit stuk geheugen al niet terugkeert naar de heap, d.w.z. het zal "lekken". De prijs voor het gebruik van lichte kopieën is het verlies van de mogelijkheid om gemakkelijk vast te stellen (zoals het zou zijn bij het gebruik van gewone kopieën) in welk filter het geheugen lekt.
Aangezien de verantwoordelijkheid voor het opsporen van geheugenlekken in de "native" filters ligt bij de ontwikkelaars van de mediastreamer, hoeft u waarschijnlijk niet te debuggen. Maar met uw zelfgemaakte filter bent u zelf de smid van uw geluk en is de tijd die u besteedt aan het zoeken naar lekken in uw code afhankelijk van uw nauwkeurigheid. Om uw ellende met debuggen te minimaliseren, moeten we de technieken voor lokalisatie van lekken bij de ontwikkeling van filters bekijken. Bovendien kan het zo zijn dat een lek zich alleen manifesteert bij het toepassen van het filter in een echt systeem, waar het aantal "verdachten" enorm kan zijn en de tijd voor debuggen beperkt.
Hoe manifesteert een geheugenlek zich?
Logischerwijs zou het moeten verschijnen in de uitvoer van het programma top waarin een toenemend percentage geheugen dat door uw toepassing wordt gebruikt, wordt weergegeven.
Het externe symptoom zal zijn dat het systeem op een bepaald moment traag zal reageren op muisbewegingen en langzaam het scherm zal vernieuwen. Het systeemlogboek kan ook groeien en schijfruimte op de harde schijf verbruiken. Ondertussen zal uw applicatie vreemd gedrag vertonen, niet reageren op opdrachten, geen bestanden kunnen openen, enzovoort.
Om vast te stellen of er een lek is ontstaan, zullen we een geheugenanalyseprogramma gebruiken (hierna de analyzer genoemd). Dit kan zijn Valgrind (een goed over deze) of ingebouwd in de compiler gcc of iets anders. Als de analyzer aangeeft dat er een lek optreedt in een van de filters van de grafiek, betekent dit dat het tijd is om een van de onderstaande methoden toe te passen.
De methode van de drie dennen
Zoals eerder vermeld, zal de analyzer bij een geheugenlek wijzen op het filter dat om geheugen uit de heap heeft gevraagd. Maar deze zal niet wijzen op het filter dat "vergat" het terug te geven, dat in feite de schuldige is. Hierdoor kan de analyzer alleen onze vermoedens bevestigen, maar niet de oorzaak aanwijzen.
Om de locatie van het "slechte" filter in de grafiek te achterhalen, kan men het pad volgen van het reduceren van de grafiek tot het minimale aantal knooppunten waarbij de analyzer nog steeds een lek detecteert en vervolgens in de overgebleven drie dennen het probleemfilter lokaliseert.
Maar het kan gebeuren dat het verkleinen van het aantal filters in de grafiek de normale interactie tussen de filters en andere elementen van uw systeem verstoort, en het lek niet meer zichtbaar is. In dat geval zal je met de volledige grafiek moeten werken en de aanpak gebruiken die hieronder wordt beschreven.
De methode van de glijdende isolator
Voor de eenvoud gebruiken we een grafiek die bestaat uit een keten van filters. Deze is weergegeven in de afbeelding.
![]()
Een normale grafiek, waarbij naast de standaard filters van de media-streamer vier handgemaakte filters F1…F4 van vier verschillende types zijn toegepast, waarvan u zeker weet dat ze correct zijn. Laten we echter aannemen dat er in een aantal daarvan een geheugenlek aanwezig is. Door ons programma voor het toezicht van de analyzer te starten, ontdekken we uit zijn rapport dat een bepaalde filter een bepaalde hoeveelheid geheugen heeft opgevraagd en dit een aantal keren niet heeft teruggegeven aan de heap. Het is gemakkelijk te raden dat er een verwijzing zal zijn naar interne functies van de filter, zoals MS_VOID_SOURCE. Het doel hiervan is om geheugen uit de heap te halen. Andere filters zouden het terug moeten geven. Dit betekent dat we een geheugenlek hebben ontdekt.
Om te bepalen op welk deel van de keten de inactiviteit heeft plaatsgevonden die tot het geheugenlek heeft geleid, wordt voorgesteld een extra filter in te voeren dat eenvoudigweg berichten van de ingang naar de uitgang doorverbindt, maar daarbij een zware kopie van het binnenkomende bericht maakt, waarna het oorspronkelijke bericht volledig wordt verwijderd. We zullen zo'n filter een isolator noemen. We veronderstellen dat aangezien de filter eenvoudig is, een lek hierin uitgesloten is. En een andere positieve eigenschap is dat als we deze op een willekeurige plaats in onze grafiek toevoegen, dit geen invloed zal hebben op de werking van het schema. We zullen de isolatorfilter afbeelden als een cirkel met een dubbele omtrek.
We schakelen de isolator direct in na de voidsource-filter:
![]()
We starten het programma opnieuw met de analyzer en zien dat de analyzer deze keer de schuld op de isolator zal leggen. Immers, het is hij die nu de datablocks creëert die vervolgens verloren gaan door een onbekende foute filter (of filters). De volgende stap is om de isolator één filter naar rechts in de keten te verschuiven en opnieuw een analyse uit te voeren. Zo, stap voor stap de isolator naar rechts verschuivend, zullen we een situatie krijgen waarin het aantal "gelekte" geheugenblokken in het volgende rapport van de analyzer zal afnemen. Dit betekent dat de isolator op dit punt in de keten precies na de defecte filter is beland. Als er maar één "slechte" filter was, zal het lek helemaal verdwijnen. Op deze manier hebben we de probleemfilter gelokaliseerd (of een van de meerdere). Door de filter te "repareren" kunnen we de isolator blijven verschuiven naar rechts in de keten tot we volledig van de geheugenlekken af zijn.
Implementatie van de isolatorfilter
De implementatie van de isolator ziet eruit als een gewone filter. Kopbestanden:
/* Файл iso_filter.h Описание изолирующего фильтра. */
#ifndef iso_filter_h
#define iso_filter_h
/* Задаем идентификатор фильтра. */
#include <mediastreamer2/msfilter.h>
#define MY_ISO_FILTER_ID 1024
extern MSFilterDesc iso_filter_desc;
#endif
De filter:
/* Файл iso_filter.c Описание изолирующего фильтра. */
#include "iso_filter.h"
static void
iso_init (MSFilter * f)
{
}
static void
iso_uninit (MSFilter * f)
{
}
static void
iso_process (MSFilter * f)
{
mblk_t *im;
while ((im = ms_queue_get (f->inputs[0])) != NULL)
{
ms_queue_put (f->outputs[0], copymsg (im));
freemsg (im);
}
}
static MSFilterMethod iso_methods[] = {
{0, NULL}
};
MSFilterDesc iso_filter_desc = {
MY_ISO_FILTER_ID,
"iso_filter",
"A filter that reads from input and copy to its output.",
MS_FILTER_OTHER,
NULL,
1,
1,
iso_init,
NULL,
iso_process,
NULL,
iso_uninit,
iso_methods
};
MS_FILTER_DESC_EXPORT (iso_desc)
Methode voor het vervangen van geheugentoegangfuncties
Voor meer gedetailleerd onderzoek biedt de mediastreamer de mogelijkheid om de toegang tot geheugensfuncties te vervangen door uw eigen, die naast hun primaire functie zullen registreren "Wie, waar en waarom". Drie functies worden vervangen. Dit gebeurt als volgt:
OrtpMemoryFunctions reserv;
OrtpMemoryFunctions my;
reserv.malloc_fun = ortp_malloc;
reserv.realloc_fun = ortp_realloc;
reserv.free_fun = ortp_free;
my.malloc_fun = &my_malloc;
my.realloc_fun = &my_realloc;
my.free_fun = &my_free;
ortp_set_memory_functions(&my);Dit biedt een uitkomst in geval de analyser de filters zo erg vertraagt dat de werking van het systeem waarin onze opzet is ingebouwd, wordt verstoord. In zo'n situatie moet men de analyzer opgeven en gebruik maken van het vervangen van geheugentoegangfuncties.
We hebben het actie-algoritme voor een eenvoudige grafiek zonder vertakkingen bekeken. Maar deze aanpak kan natuurlijk ook voor andere gevallen worden toegepast, weliswaar met complicaties, maar het idee blijft hetzelfde.
In het volgende artikel zullen we de vraag bespreken over de belastingsevaluatie voor de ticker en manieren om overmatige rekenbelasting in de mediastreamer te bestrijden.
Bron: habr.com
