Artikelmaterialet Àr hÀmtat frÄn min .

Tidigare , jag lovade att övervÀga frÄgan om belastningsbedömning av tickern och metoder för att hantera överdriven datorkraft i mediastreamern. Men jag beslutade att det skulle vara mer logiskt att belysa frÄgor om felsökning av skrÀddarsydda filter, relaterade till datarörelser, och först dÀrefter ta upp frÄgor om prestandaoptimering.
Felsökning av skrÀddarsydda filter
Efter att vi i den föregÄende artikeln diskuterade mekanismen för datarörelser i mediastreamern, vore det logiskt att prata om de faror som döljer sig inom den. En av sÀrdragen med principen "data flow" Àr att minnesallokeringen frÄn heapen sker i filter som ligger vid kÀllan till datastreamen, medan frigöring av minnet med ÄterlÀmning till heapen görs av filter som Àr placerade i slutet av datastreamen. Dessutom kan skapandet och destruktionen av nya data ske nÄgonstans i intermediÀra punkter. I allmÀnhet utförs minnesfrigöring inte av det filter som skapade datablocket.
Ur perspektivet av transparent övervakning av minnet skulle det vara rimligt att filter, nĂ€r de fĂ„r en ingĂ„ngsblock, efter bearbetning omedelbart förstör det och frigör minnet, medan de pĂ„ utsidan skulle presentera det nyligen skapade blocket med utdata. I det hĂ€r fallet skulle minneslĂ€ckan i filtret lĂ€tt kunna spĂ„ras â om analysatorn upptĂ€ckte en lĂ€cka i filtret, innebĂ€r det att nĂ€sta filter efter det inte förstör ingĂ„ngsblocken pĂ„ rĂ€tt sĂ€tt och att det Ă€r en fel i det. Men med avseende pĂ„ att upprĂ€tthĂ„lla hög prestanda, Ă€r en sĂ„dan metod för att hantera datablokkar, inte produktiv â den leder till ett stort antal operationer för allokering/frigöring av minne för datablokkar utan nĂ„got nyttigt utbyte.
Av denna anledning anvÀnder mediastreamerfilter funktioner som skapar lÀtta kopior vid kopiering av meddelanden för att inte sakta ner databehandlingen (vi har berÀttat om dem i vÄr tidigare artikel). Dessa funktioner skapar bara en ny instans av meddelandets rubrik genom att "fÀsta" en datablack frÄn det kopierade "gamla" meddelandet till den. Som ett resultat Àr tvÄ rubriker kopplade till en enda datablack och referensrÀknaren i datablocket ökas. Men detta kommer att se ut som tvÄ meddelanden. Det kan finnas fler meddelanden med en sÄdan "delad" datablack; till exempel genererar filtret MS_TEE genast ett dussin av dessa lÀtta kopior och fördelar dem över sina utgÄngar. Vid korrekt funktion av alla filter i kedjan, bör denna referensrÀknare nÄ noll i slutet av processen, och funktionen för minnesfrisÀttning kommer att anropas: ms_free(). Om anropet inte sker, betyder det att detta minnesblock redan inte kommer att ÄtergÄ till högen, det vill sÀga det kommer att "lÀcka". Priset för att anvÀnda lÀtta kopior Àr förlusten av möjligheten att enkelt identifiera (som det skulle vara med vanliga kopior) i vilket filter minnet lÀcker.
Eftersom ansvaret för att upptÀcka minneslÀckor i "inbyggda" filter ligger pÄ utvecklarna av mediastreamern, kommer du troligen inte att behöva felsöka dem. Men med ditt egenutvecklade filter Àr du sjÀlv smeden av din lycka, och din noggrannhet kommer att pÄverka den tid du lÀgger pÄ att leta efter lÀckor i din kod. För att minska din tid vid felsökning bör vi övervÀga tekniker för att lokalisera lÀckor vid filterutveckling. Dessutom kan det hÀnda att en lÀcka bara visar sig nÀr filtret tillÀmpas i ett verkligt system, dÀr antalet "misstÀnkta" kan vara enormt och tiden för felsökning begrÀnsad.
Hur visar sig en minneslÀcka?
Det Àr logiskt att anta att i programmets utdata top kommer en ökande procentandel av minnet som anvÀnds av din applikation att visas.
Det yttre tecknet kommer att vara att systemet vid nÄgon tidpunkt blir lÄngsamt att reagera pÄ musrörelser och lÄngsamt Äterger skÀrmen. Det kan ocksÄ hÀnda att systemlogg ökar, vilket tar upp utrymme pÄ hÄrddisken. Under tiden kommer din applikation att börja bete sig mÀrkligt, inte svara pÄ kommandon, inte kunna öppna filer osv.
För att identifiera förekomsten av en lÀcka kommer vi att anvÀnda en minnesanalysator (hÀdanefter analysator). Det kan vara Valgrind (bra om den) eller inbyggd i kompilatorn gcc eller nÄgot annat. Om analysatorn visar att lÀckan intrÀffar i nÄgon av filtren i grafen, betyder det att det Àr dags att anvÀnda en av metoderna som beskrivs nedan.
Tre pinjetrÀd-metoden
Som tidigare nÀmnts, vid minneslÀckor kommer analysatorn att peka ut filtret som begÀrde minnesallokering frÄn heapen. Men den kommer inte att peka ut filtret som "glömde" att ÄterlÀmna det, vilket faktiskt Àr den skyldige. PÄ sÄ sÀtt kan analysatorn bara bekrÀfta vÄra farhÄgor, men inte ange deras rot.
För att ta reda pÄ platsen för det "otÀcka" filtret i grafen kan man gÄ vÀgen att minska grafen till minsta antalet noder dÀr analysatorn fortfarande upptÀcker lÀckan och i de kvarvarande tre pinjetrÀden lokalisera det problematiska filtret.
Men det kan hÀnda att om du minskar antalet filter i grafen bryter du den vanliga interaktionen mellan filtren och andra element i ditt system och lÀckan slutar att manifesteras. I detta fall mÄste du arbeta med den fullstÀndiga grafen och anvÀnda tillvÀgagÄngssÀttet som beskrivs nedan.
Glidande isolator-metoden
För enkelhetens skull kommer vi att anvÀnda en graf som bestÄr av en kedja av filter. Den Àr avbildad i bilden.
![]()
En vanlig graf dĂ€r, tillsammans med de fĂ€rdiga filtren för medieströmmen, tillĂ€mpas fyra hantverksfilter F1âŠF4 av fyra olika typer som du skapade för lĂ€nge sedan och vars korrekthet du inte tvivlar pĂ„. Anta Ă€ndĂ„ att det finns minneslĂ€ckor i nĂ„gra av dem. NĂ€r vi kör vĂ„rt övervakningsprogram med analyzatorn fĂ„r vi veta frĂ„n dess rapport att ett visst filter har begĂ€rt en viss mĂ€ngd minne och inte Ă„terlĂ€mnat det till högen ett visst antal gĂ„nger. Det Ă€r lĂ€tt att gissa att det kommer att hĂ€nvisas till interna funktioner för filtertypen MS_VOID_SOURCE. Dess uppgift Ă€r att hĂ€mta minne frĂ„n högen. Andra filter bör Ă„terlĂ€mna det dit. Det vill sĂ€ga, vi upptĂ€cker ett faktum om en lĂ€cka.
För att faststÀlla var pÄ enheten av transportbandet som inaktiviteten intrÀffade och ledde till minneslÀckan, föreslÄs det att införa ett extra filter som helt enkelt överför meddelanden frÄn ingÄngen till utgÄngen, men skapar en tung kopia av ingÄngsmeddelandet och tar bort meddelandet som kom till ingÄngen. Vi kommer att kalla detta filter isolator. Vi antar att eftersom filtret Àr enkelt sÄ Àr lÀckan utesluten i det. En annan positiv egenskap Àr att om vi lÀgger till det i vilket som helst avsnitt av vÄr graf, sÄ pÄverkar det inte schemat. Vi kommer att avbilda isolatorfiltret som en cirkel med dubbel kontur.
Vi aktiverar isolatorn direkt efter filtret voidsource:
![]()
Vi kör programmet igen med analyzatorn och ser att den hÀr gÄngen lÀgger analysatorn skulden pÄ isolatorn. För det Àr det nu som skapar datablokkar som sedan gÄr förlorade av en okÀnd slarvig filter (eller filter). NÀsta steg Àr att flytta isolatorn en position till höger i kedjan, en filter, och köra analysen igen. SÄ, steg för steg, genom att flytta isolatorn till höger, kommer vi att fÄ en situation dÀr antalet "lÀckta" minnesblock i den kommande rapporten frÄn analyzatorn minskar. Det betyder att vid det hÀr steget befann sig isolatorn just efter det problematiska filtret. Om det "dÄliga" filtret var det enda, försvinner lÀckan helt. PÄ sÄ sÀtt har vi lokaliserat det problematiska filtret (eller en av flera). "Genom att laga" filtret kan vi fortsÀtta att flytta isolatorn till höger i kedjan tills vi helt har besegrat minneslÀckorna.
Implementering av isolatorfiltret
Implementeringen av isolatorn ser ut som en vanlig filter. Rubrikfil:
/* ЀаĐčĐ» 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
SjÀlva filtret:
/* ЀаĐčĐ» 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)
Metod för att ersÀtta minneshanteringsfunktioner
För mer detaljerade undersökningar finns det en funktion i mediastreamern för att ersÀtta minnesÄtkomstfunktioner med egna, som förutom det primÀra arbetet ocksÄ registrerar "Vem, vart och varför". Tre funktioner ersÀtts. Det görs pÄ följande sÀtt:
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);Denna möjlighet Àr vÀrdefull nÀr analysatorn saktar ner filterens arbete sÄ mycket att det pÄverkar systemets funktioner som vÄr schema Àr integrerad i. I en sÄdan situation mÄste man avstÄ frÄn analysatorn och anvÀnda ersÀttningsfunktioner för minneshantering.
Vi har gÄtt igenom handlingsalgoritmen för en enkel graf utan förgreningar. Men denna metod kan ocksÄ tillÀmpas pÄ andra situationer, sjÀlvklart med mer komplexitet, men idén kommer att förbli densamma.
I nÀsta artikel kommer vi att titta pÄ hur man bedömer belastningen pÄ tickern och hur man hanterar överdriven berÀkningsbelastning i mediastreamern.
KĂ€lla: habr.com
