Kako sam istraživao curenje memorije u Gou koristeći pprof na velikoj bazi koda

Radim s Goom veći dio godine, implementirajući prilagodljivu blockchain infrastrukturu u Orbsu, a bila je to uzbudljiva godina. Tijekom 2018. istraživali smo koji jezik odabrati za našu implementaciju blockchaina. To nas je navelo da odaberemo Go zbog našeg razumijevanja da ima dobru zajednicu i nevjerojatan set alata.

Posljednjih tjedana ulazimo u završnu fazu integracije našeg sustava. Kao u bilo kojem velikom sustavu, mogu se pojaviti problemi u kasnijoj fazi koji uključuju probleme s izvedbom, u određenim curenjima memorije. Dok smo integrirali sustav, shvatili smo da smo ga pronašli. U ovom ću se članku dotaknuti specifičnosti kako istražiti curenje memorije u programu Go, detaljno opisujući korake za njegovo pronalaženje, razumijevanje i rješavanje.

Komplet alata koji nudi Golang je izuzetan, ali ima svoja ograničenja. Dotaknuvši ih prvo, najveća je ograničena mogućnost istraživanja deponija pune jezgre. Dump pune jezgre bila bi slika memorije (ili korisničke memorije) koju je snimio postupak u kojem se izvodi program.

Možemo zamisliti mapiranje memorije kao stablo, a prelazak tog stabla vodio bi nas kroz različite alokacije objekata i relacije. To znači da je ono što je u korijenu razlog zašto se memorija zadržava, a ne GCing (Skupljanje smeća). Budući da u Gou ne postoji jednostavan način za analizu dump-a pune jezgre, teško je doći do korijena objekta koji ne dobiva GC-ed.

U vrijeme pisanja ovog članka na mreži nismo uspjeli pronaći nijedan alat koji bi nam mogao pomoći u tome. Budući da postoji osnovni format dump-a i dovoljno jednostavan način za izvoz iz paketa za otklanjanje pogrešaka, moguće je da se jedan koristi na Googleu. Pretražujući putem interneta, čini se da se nalazi u cjevovodu Golang, stvarajući jezgroviti preglednik istovara, ali ne izgleda kao da itko na tome radi. Rekavši to, čak i bez pristupa takvom rješenju, s postojećim alatima obično možemo doći do temeljnog uzroka.

Curenje memorije

Curenje memorije ili pritisak memorije mogu se pojaviti u mnogim oblicima u cijelom sustavu. Obično ih oslovljavamo s programskim pogreškama, ali ponekad njihov osnovni uzrok mogu biti odluke u dizajnu.

Kako svoj sustav gradimo prema novim principima dizajna, ne vjeruje se da su takva razmatranja važna i to je u redu. Važnije je sustav izraditi na način koji izbjegava preuranjene optimizacije i omogućuje vam da ih kasnije izvodite dok sazrijeva kôd, a ne da ga prekomjerno projektirate od samog početka. Ipak, neki uobičajeni primjeri kako se materijalizirani problemi s pritiskom pojavljuju:

  • Previše dodjela, netočno predstavljanje podataka
  • Teška upotreba refleksije ili žica
  • Korištenje globala
  • Bez roditelja, beskrajne goroutine

U programu Go najjednostavniji način stvaranja curenja memorije je definiranje globalne varijable, niza i dodavanje podataka u taj niz. Ovaj sjajni post na blogu na dobar način opisuje taj slučaj.

Pa zašto pišem ovaj post? Kad sam istraživao ovaj slučaj, našao sam mnogo izvora o curenju memorije. Ipak, u stvarnosti sustavi imaju više od 50 linija koda i jednu strukturu. U takvim je slučajevima pronalazak izvora problema s memorijom mnogo složeniji od onoga što opisuje taj primjer.

Golang nam daje nevjerojatan alat tzv pprof. Kad se svlada ovaj alat, može pomoći u istraživanju i najvjerojatnije pronalaženju bilo kojeg problema s memorijom. Još jedna svrha koju ima ima za istraživanje problema s procesorom, ali u ovom postu neću ulaziti u ništa vezano uz CPU.

go alat pprof

Za pokrivanje svega što ovaj alat zahtijeva više od jednog bloga. Jedna stvar koja je potrajala je saznati kako koristiti ovaj alat da biste postigli nešto za djelovanje. Koncentrirat ću ovaj post na njegovu memorijsku značajku.

pprofPaket stvara gomila uzorkovana dump datoteku koja kasnije možete analizirati / vizualizirati kako bi vam dati kartu i:

  • Trenutna dodjela memorije
  • Ukupna (kumulativna) dodjela memorije

Alat ima mogućnost usporedbe snimaka. To vam može omogućiti usporedbu prikaza vremenskih razlika onoga što se dogodilo sada i prije 30 sekundi, na primjer. Za scenarije stresa ovo može biti korisno za pomoć u pronalaženju problematičnih područja koda.

pprof profili

Način rada pprof-a je pomoću profila.

Profil je zbirka tragova snopa koji prikazuju sekvence poziva koje su dovele do instanci određenog događaja, poput dodjele.

Datoteka runtime / pprof / pprof.go sadrži detaljne informacije i implementaciju profila.

Go ima nekoliko ugrađenih profila za upotrebu u uobičajenim slučajevima:

  • goroutine - stogovi svih trenutnih goroutina
  • hrpa - uzorkovanje raspodjele memorije živih objekata
  • allocs - uzorak svih prošlih dodjela memorije
  • threadcreate - tragovi stoga koji su doveli do stvaranja novih OS niti
  • block - stack tragovi koji su doveli do blokiranja na primitivima sinkronizacije
  • mutex - tragovi stoga držača spornih muteksa

Kada promatramo probleme s memorijom, koncentrirat ćemo se na profil hrpe. Profil allocs identičan je s obzirom na prikupljanje podataka koje obavlja. Razlika između njih dvije je način na koji alat pprof tamo čita u vrijeme početka. Allocs profil pokrenut će pprof u načinu koji prikazuje ukupan broj dodijeljenih bajtova od početka programa (uključujući bajtove prikupljene smećem). Obično ćemo koristiti taj način kada pokušavamo učiniti naš kod učinkovitijim.

Gomila

Apstraktno, ovdje OS (Operativni sustav) pohranjuje memoriju objekata koje naš kod koristi. Ovo je memorija koja kasnije dobiva 'prikupljeno smeće' ili ga ručno oslobađa na jezicima koji se ne prikupljaju.

Hrpa nije jedino mjesto na kojem se događaju alokacije memorije, dio memorije je također dodijeljen u stogu. Svrha steka je kratkoročna. U Go stog se obično koristi za zadatke koji se događaju unutar zatvaranja funkcije. Još jedno mjesto na kojem Go koristi stek je kada kompajler 'zna' koliko memorije treba rezervirati prije vremena izvođenja (npr. Nizovi fiksne veličine). Postoji način da se pokrene kompajler Go, tako da će se dati analiza gdje alokacije 'pobjegnu' iz hrpe u hrpu, ali to neću dotaknuti u ovom postu.

Iako podatke hrpe treba 'osloboditi' i gc-editirati, podaci steka to ne čine. To znači da je puno učinkovitije koristiti stog gdje je to moguće.

Ovo je sažetak različitih mjesta na kojima se događa dodjela memorije. Puno je toga više, ali ovo će biti izvan dosega ovog posta.

Dobivanje podataka o hrpi pomoću pprof

Postoje dva glavna načina za dobivanje podataka za ovaj alat. Prva će obično biti dio testa ili grane i uključuje uvoz, runtime/pprofa zatim poziv pprof.WriteHeapProfile(some_file)za pisanje podataka o hrpi.

Imajte na umu da WriteHeapProfileje sintaksički šećer za trčanje:

// lookup takes a profile namepprof.Lookup("heap").WriteTo(some_file, 0)

Prema dokumentima, WriteHeapProfilepostoji radi povratne kompatibilnosti. Ostali profili nemaju takve prečace i morate koristiti Lookup()funkciju da biste dobili njihove podatke o profilu.

Druga, koja je zanimljivija, jest omogućiti je putem HTTP-a (krajnjih točaka utemeljenih na webu). To vam omogućuje izvlačenje podataka adhoc, iz spremnika koji se izvodi u vašem e2e / test okruženju ili čak iz 'proizvodnje'. Ovo je još jedno mjesto gdje Go Runtime i set alata briljiraju. Cjelokupna dokumentacija o paketu nalazi se ovdje, ali TL; DR je da ćete je trebati dodati u svoj kôd kao takav:

import ( "net/http" _ "net/http/pprof")
...
func main() { ... http.ListenAndServe("localhost:8080", nil)}

'Nuspojava' uvoza net/http/pprofje registracija krajnjih točaka pprof pod korijenom web poslužitelja na /debug/pprof. Sada pomoću curla možemo dobiti datoteke s podacima o hrpi koje ćemo istražiti:

curl -sK -v //localhost:8080/debug/pprof/heap > heap.out

Dodavanje http.ListenAndServe()gore navedenog potrebno je samo ako vaš program prije nije imao http slušatelj. Ako ga imate, spojit će ga i nema potrebe za ponovnim slušanjem. Postoje i načini postavljanja pomoću a ServeMux.HandleFunc()koji bi imao više smisla za složeniji program s omogućenom http.

Korištenjem pprof

Dakle, prikupili smo podatke, što sada? Kao što je gore spomenuto, postoje dvije glavne strategije analize memorije s pprofom. Jedan je oko gledanja trenutnih dodjela (bajtova ili broja objekata), pozvanih inuse. Drugi gleda na sve dodijeljene bajtove ili broj objekata tijekom vremena izvođenja programa, pozvanog alloc. To znači, bez obzira je li to gc-ed, zbroj svega uzorkovanog.

Ovo je dobro mjesto za ponoviti da je profil hrpe uzorak dodjela memorije . pprofiza scene koristi runtime.MemProfilefunkciju koja prema zadanim postavkama prikuplja podatke o dodjeli na svakih 512 KB dodijeljenih bajtova. Moguće je promijeniti MemProfile za prikupljanje podataka o svim objektima. Napominjemo da će ovo najvjerojatnije usporiti vašu prijavu.

To znači da prema zadanim postavkama postoji šansa da se problem dogodi s manjim objektima koji će skliznuti ispod pprofovog radara. Za veliku bazu kodnih programa / dugotrajni program to nije problem.

Nakon što prikupimo datoteku profila, vrijeme je da je učitamo u interaktivnu konzolu koju nudi pprof. Učinite to trčanjem:

> go tool pprof heap.out

Promatrajmo prikazane informacije

Type: inuse_spaceTime: Jan 22, 2019 at 1:08pm (IST)Entering interactive mode (type "help" for commands, "o" for options)(pprof)

Ovdje je važno napomenuti Type: inuse_space. To znači da gledamo podatke o raspodjeli određenog trenutka (kada smo uhvatili profil). Tip je vrijednost konfiguracije sample_index, a moguće vrijednosti su:

  • inuse_space - količina dodijeljene i još neoslobođene memorije
  • inuse_object s - količina dodijeljenih i još neobjavljenih objekata
  • alloc_space - ukupna količina dodijeljene memorije (bez obzira na izdanu)
  • alloc_objects - ukupna količina dodijeljenih objekata (bez obzira na objavljene)

Sada unesite topinteraktivni, izlaz će biti najveći potrošači memorije

Vidimo redak koji nam govori o tome Dropped Nodes, što znači da su filtrirani. Čvor je unos objekta ili 'čvor' u stablu. Ispuštanje čvorova dobra je ideja za smanjenje neke buke, ali ponekad može sakriti osnovni uzrok problema s memorijom. Primjer za to vidjet ćemo tijekom nastavka istrage.

Ako želite uključiti sve podatke profila, dodajte -nodefraction=0opciju prilikom pokretanja pprof ili unesite nodefraction=0interaktivnu.

Na izlaznom popisu možemo vidjeti dvije vrijednosti flati cum.

  • stan znači da memorija koju dodjeljuje ova funkcija i koju ta funkcija zadržava
  • cum znači da je memorija dodijeljena ovom funkcijom ili funkcijom koju je pozvala u niz

Samo ove informacije ponekad nam mogu pomoći da shvatimo postoji li problem. Uzmimo za primjer slučaj kada je funkcija odgovorna za dodjelu puno memorije, ali je ne zadržava. To bi značilo da neki drugi objekt pokazuje na tu memoriju i drži je dodijeljenom, što znači da možemo imati problem s dizajnom sustava ili grešku.

Još jedan zgodan trik topu interaktivnom prozoru je da se on zapravo izvodi top10. Naredba top podržava topNformat gdje Nje broj unosa koje želite vidjeti. U gore zalijepljenom slučaju, top70na primjer tipkanjem, izlazili bi svi čvorovi.

Vizualizacije

Iako topNdaje tekstualni popis, postoji nekoliko vrlo korisnih opcija vizualizacije koje dolaze s pprofom. Moguće je tipkati pngili gifi još mnogo toga (pogledajte go tool pprof -helpcijeli popis).

U našem sustavu zadani vizualni izlaz izgleda otprilike ovako:

To u početku može zastrašivati, ali to je vizualizacija tokova dodjele memorije (prema tragovima stoga) u programu. Čitanje grafa nije tako komplicirano kako izgleda. Bijeli kvadrat s brojem prikazuje dodijeljeni prostor (i kumulativ koliko memorije zauzima trenutno na rubu grafikona), a svaki širi pravokutnik prikazuje funkciju dodjeljivanja.

Imajte na umu da sam na gornjoj slici uzeo png iz inuse_spacenačina izvršavanja. Mnogo puta biste trebali i to pogledati inuse_objects, jer to može pomoći u pronalaženju problema s raspodjelom.

Kopajući dublje, pronalazeći glavni uzrok

Do sada smo mogli razumjeti što dodjeljuje memoriju u našoj aplikaciji tijekom izvođenja. To nam pomaže da steknemo osjećaj kako se naš program ponaša (ili se loše ponaša).

U našem bismo slučaju mogli vidjeti da memoriju zadržava membuffers, a to je naša knjižnica za serializaciju podataka. To ne znači da na tom segmentu koda imamo curenje memorije, to znači da ta funkcija zadržava memoriju. Važno je razumjeti kako čitati graf i općenito izlaz pprof-a. U ovom slučaju, razumijevanje da kada serializiramo podatke, što znači da alociramo memoriju na strukture i primitivne objekte (int, string), oni se nikada ne oslobađaju.

Preskačući zaključke ili pogrešno tumačeći graf, mogli smo pretpostaviti da je jedan od čvorova na putu do serializacije odgovoran za zadržavanje memorije, na primjer:

Negdje u lancu možemo vidjeti našu knjižnicu dnevnika, odgovornu za> 50 MB dodijeljene memorije. Ovo je memorija koja se dodjeljuje funkcijama koje naziva naš zapisnik. Razmišljajući, ovo se zapravo očekuje. Logger uzrokuje dodjelu memorije jer treba serializirati podatke za njihov izlaz u dnevnik, a time uzrokuje i dodjelu memorije u procesu.

Također možemo vidjeti da se niz put dodjele memorija zadržava samo serializacijom i ničim drugim. Uz to, količina memorije koju zapisovač zadržava iznosi oko 30% od ukupne količine. Navedeno nam govori da, najvjerojatnije, problem nije u drvosječi. Ako je bilo 100% ili nešto slično, onda smo trebali tražiti tamo - ali nije. Što bi moglo značiti jest da se bilježi nešto što ne bi trebalo biti, ali to nije propuštanje memorije od strane zapisničara.

Povoljan je trenutak za uvođenje druge pprofnaredbe koja se zove list. Prihvaća regularni izraz koji će biti filtar onoga što treba navesti. 'Popis' je zapravo anotirani izvorni kod koji se odnosi na dodjelu. U kontekstu logera kojeg istražujemo, izvršit ćemo list RequestNewonako kako bismo željeli vidjeti pozive upućene logeru. Ti pozivi dolaze iz dviju funkcija koje počinju istim prefiksom.

Vidimo da su dodijeljena sjedišta u cumstupcu, što znači da se dodijeljena memorija zadržava u nizu poziva. To odgovara onome što grafikon također pokazuje. U tom je trenutku lako uočiti da je razlog zbog kojeg je zapisovač alocirao memoriju taj što smo mu poslali cijeli objekt 'blok'. Trebalo je barem neke njegove dijelove serializirati (naši su objekti membuffer objekti, koji uvijek implementiraju neku String()funkciju). Je li to korisna poruka dnevnika ili dobra praksa? Vjerojatno nije, ali to nije curenje memorije, niti na kraju zapisnika ili kôd koji je nazvao zapisovač.

listmožete pronaći izvorni kod dok ga tražite u vašem GOPATHokruženju. U slučajevima kada se korijen koji traži ne podudara, što ovisi o vašem stroju za izradu, možete koristiti -trim_pathopciju. To će vam pomoći da ga popravite i omogućite vam da vidite anotirani izvorni kod. Ne zaboravite postaviti svoj git na pravo urezivanje koje je bilo pokrenuto kad je snimljen profil hrpe.

Pa zašto se zadržava memorija?

Pozadina ove istrage bila je sumnja da imamo problem - curenje memorije. Došli smo do tog pojma jer smo vidjeli da je potrošnja memorije veća od one koju bismo očekivali da će sustav trebati. Povrh svega, vidjeli smo kako se to neprestano povećava, što je bio još jedan snažan pokazatelj „ovdje postoji problem“.

U ovom trenutku, u slučaju Jave ili .Net-a, otvorili bismo analizu ili profiler 'gc root' i došli do stvarnog objekta koji se poziva na te podatke i stvara curenje podataka. Kao što je objašnjeno, to s Goom nije točno moguće, i zbog problema s alatima, ali i zbog Goove reprezentacije memorije na niskoj razini.

Ne ulazeći u detalje, ne mislimo da Go zadržava koji je objekt pohranjen na kojoj adresi (osim možda pokazivača). To znači da će u stvarnom razumijevanju koja memorijska adresa predstavlja člana vašeg objekta (strukture) biti potrebno nekakvo preslikavanje na izlaz heap profila. Teoretski govoreći, to bi moglo značiti da prije snimanja cjelovite dump-datoteke treba uzeti i profil hrpe kako bi se adrese mogle preslikati u liniju i datoteku za dodjelu, a time i na objekt predstavljen u memoriji.

U ovom trenutku, jer smo upoznati s našim sustavom, bilo je lako shvatiti da ovo više nije bug. Bilo je to (gotovo) po dizajnu. Ali nastavimo istraživati ​​kako doći do podataka iz alata (pprof) kako bismo pronašli osnovni uzrok.

Prilikom postavljanja nodefraction=0vidjet ćemo cijelu kartu dodijeljenih objekata, uključujući i manje. Pogledajmo izlaz:

Imamo dva nova podstabla. Podsjećam opet, pprof heap profil uzorkuje dodjelu memorije. Za naš sustav koji funkcionira - ne nedostaju nam važne informacije. Duže novo stablo, zelene boje, koje je potpuno odvojeno od ostatka sustava, je test trkač, nije zanimljivo.

Kraći je, plave boje, koji ima rub koji ga povezuje s cijelim sustavom inMemoryBlockPersistance. To ime također objašnjava 'curenje' koje smo zamislili da imamo. Ovo je pozadina podataka koja sprema sve podatke u memoriju i ne zadržava se na disku. Ono što je lijepo primijetiti jest da smo odmah mogli vidjeti da se u njemu nalaze dva velika predmeta. Zašto dva? Budući da možemo vidjeti da je objekt veličine 1,28 MB, a funkcija zadržava 2,57 MB, što znači dva od njih.

U ovom je trenutku problem dobro shvaćen. Mogli smo upotrijebiti delve (program za ispravljanje pogrešaka) kako bismo vidjeli da je ovo niz koji sadrži sve blokove za pokretački program postojanosti u memoriji koji imamo.

Pa što bismo mogli popraviti?

Pa, to je bilo sranje, to je bila ljudska pogreška. Iako se proces educirao (a dijeljenje je brižno), nismo postali bolji, ili nismo?

Jedna je stvar još uvijek "mirisala" u vezi s ovom hrpom podataka. Deserijalizirani podaci zauzimali su previše memorije, zašto 142 MB za nešto što bi trebalo znatno manje? . . pprof može odgovoriti na to - zapravo, postoji tačan odgovor na takva pitanja.

Pokrenut ćemo kako bismo pogledali anotirani izvorni kod funkcije list lazy. Koristimo lazy, kao što je ime funkcije koju tražimo, lazyCalcOffsets()i ne znamo da druge funkcije u našem kodu počinju s lijenim. Tipkanje list lazyCalcOffsetsbi također uspjelo, naravno.

Možemo vidjeti dvije zanimljive informacije. Opet, sjetite se da profil profila hrpe pprof uzorkuje informacije o dodjeli. Možemo vidjeti da su flati cumbrojevi i brojevi isti. To ukazuje da ove dodijeljene točke zadržavaju i dodijeljenu memoriju.

Dalje, možemo vidjeti da make () uzima malo memorije. To ima smisla, to je pokazivač na strukturu podataka. Ipak, također vidimo da dodjela u retku 43 zauzima memoriju, što znači da stvara dodjelu.

Ovo nas je educiralo o kartama, gdje dodjeljivanje karti nije izravno dodjeljivanje varijabli. Ovaj članak detaljno opisuje kako karta djeluje. Ukratko, karta ima režijske troškove i što više elemenata to će veći troškovi 'koštati' u usporedbi s kriškom.

S rezervom treba shvatiti sljedeće: Bilo bi u redu reći da se upotrebom a map[int]T, kada podaci nisu rijetki ili se mogu pretvoriti u sekvencijalne indekse, obično pokušava pokušati implementirati kriška ako je potrošnja memorije relevantna stvar . Ipak, velika kriška, kad se proširi, može usporiti operaciju, gdje će na karti to usporavanje biti zanemarivo. Ne postoji čarobna formula za optimizacije.

U gornjem kodu, nakon što smo provjerili kako smo koristili tu kartu, shvatili smo da je, iako smo je zamišljali kao rijetki niz, izašao kao ne tako rijedak. To se podudara s gornjim argumentom i mogli smo odmah vidjeti da je mali refaktor promjene karte u krišku zapravo moguć, a taj bi kôd mogao učiniti učinkovitijim u memoriji. Pa smo ga promijenili u:

Jednostavno, umjesto da koristimo kartu, sada koristimo krišku. Zbog načina na koji primamo podatke koji se u njih lijeno učitavaju i kako kasnije pristupamo tim podacima, osim ove dvije linije i strukture koja sadrži te podatke, nije potrebna druga promjena koda. Što je učinio na potrošnju memorije?

Pogledajmo benchcmpsamo nekoliko testova

Testovi čitanja inicijaliziraju strukturu podataka koja kreira alokacije. Vidimo da se vrijeme izvođenja poboljšalo za ~ 30%, izdvajanja su smanjena za 50%, a potrošnja memorije za> 90% (!)

Budući da karta, koja je sada izrezana, nikada nije bila ispunjena s puno predmeta, brojevi u velikoj mjeri pokazuju ono što ćemo vidjeti u proizvodnji. Ovisi o entropiji podataka, ali mogu biti slučajevi kada bi i izdvajanja i poboljšanja potrošnje memorije bili još veći.

Gledajući pprofponovno i uzimajući gomilu profila iz istog testa, vidjet ćemo da je sada potrošnja memorije zapravo smanjena za ~ 90%.

Za poneti će se primijeniti da za manje skupove podataka ne biste trebali koristiti karte tamo gdje bi kriške bile dovoljne, jer karte imaju velike troškove.

Izbacivanje cijele jezgre

Kao što je spomenuto, ovdje trenutno vidimo najveće ograničenje kod alata. Kad smo istraživali ovaj problem, bili smo opsjednuti mogućnošću da dođemo do korijenskog objekta, bez puno uspjeha. Go se s vremenom razvija velikom brzinom, ali ta evolucija ima cijenu u slučaju potpunog izbacivanja ili predstavljanja memorije. Format dump-a pune hrpe, kako se mijenja, nije kompatibilan unatrag. Ovdje je opisana najnovija verzija, a za pisanje punog izvatka hrpe možete koristiti debug.WriteHeapDump().

Iako se trenutno ne nalazimo "zaglavljeni", jer nema dobrog rješenja za istraživanje punih smetlišta. pprofodgovorio na sva naša pitanja do sada.

Primijetite, internet pamti puno informacija koje više nisu relevantne. Evo nekoliko stvari koje biste trebali zanemariti ako ćete sami pokušati otvoriti cjeloviti deponij, od go1.11:

  • Ne postoji način za otvaranje i ispravljanje pogrešaka cjelovite deponije na MacOS-u, samo na Linuxu.
  • Alati na //github.com/randall77/hprof su za Go1.3, postoji vilica za verziju 1.7+, ali ni ona ne radi ispravno (nepotpuna).
  • viewcore na //github.com/golang/debug/tree/master/cmd/viewcore zapravo se ne sastavlja. To je dovoljno jednostavno popraviti (interni paketi usmjeravaju na golang.org, a ne na github.com), ali ni to ne funkcionira , ni na MacOS-u, možda na Linuxu.
  • Također //github.com/randall77/corelib ne uspijeva na MacOS-u

pprof UI

Posljednji detalj kojeg treba biti svjestan kada je u pitanju pprof, jest njegova značajka korisničkog sučelja. To može uštedjeti puno vremena prilikom započinjanja istrage bilo kojeg problema koji se odnosi na profil snimljen s pprof.

go tool pprof -http=:8080 heap.out

Tada bi trebao otvoriti web preglednik. Ako se to ne dogodi, potražite priključak na koji ste ga postavili. Omogućuje vam promjenu opcija i dobivanje vizualnih povratnih informacija mnogo brže nego što možete iz naredbenog retka. Vrlo koristan način za trošenje informacija.

UI me zapravo upoznao s plamenskim grafikonima koji vrlo brzo otkrivaju područja krivca koda.

Zaključak

Go je uzbudljiv jezik s vrlo bogatim setom alata, puno više možete učiniti s pprof. Na primjer, ovaj post uopće ne dotiče profiliranje CPU-a.

Neka druga dobra čitanja:

  • //rakyll.org/archive/ - Vjerujem da će ovo biti jedan od glavnih suradnika u praćenju izvedbe, puno dobrih postova na njezinom blogu
  • //github.com/google/gops - napisao JBD (koji upravlja rakyll.org), ovaj alat jamči vlastiti post na blogu.
  • //medium.com/@cep21/using-go-1-10-new-trace-features-to-debug-an-integration-test-1dc39e4e812d - go tool tracešto je oko profiliranja CPU-a, ovo je sjajan post o toj značajci profiliranja .