Hvordan jeg undersøgte hukommelseslækage i Go ved hjælp af pprof på en stor codebase

Jeg har arbejdet med Go den største del af året og implementeret en skalerbar blockchain-infrastruktur på Orbs, og det har været et spændende år. I løbet af 2018 undersøgte vi, hvilket sprog vi skulle vælge til vores blockchain-implementering. Dette fik os til at vælge Go på grund af vores forståelse af, at det har et godt samfund og et fantastisk værktøjssæt.

I de seneste uger er vi i gang med de sidste faser af integrationen af ​​vores system. Som i ethvert stort system kan der opstå problemer i det senere stadium, der inkluderer ydelsesproblemer i specifikke hukommelseslækager. Da vi integrerede systemet, indså vi, at vi fandt et. I denne artikel vil jeg røre ved detaljerne i, hvordan man undersøger en hukommelseslækage i Go, med en beskrivelse af de skridt, der er taget for at finde, forstå og løse det.

Værktøjssættet, der tilbydes af Golang, er usædvanligt, men har sine begrænsninger. Når man først rører ved disse, er den største begrænsede evne til at undersøge fuld core dumps. En fuld kernedump ville være billedet af hukommelsen (eller brugerhukommelsen) taget af processen, der kører programmet.

Vi kan forestille os hukommelseskortlægningen som et træ, og at krydse dette træ ville føre os gennem de forskellige allokeringer af objekter og forholdet. Dette betyder, at uanset hvad der er ved roden, er det grunden til at 'holde' hukommelsen og ikke GCe den (Garbage Collecting). Da der i Go ikke er nogen enkel måde at analysere hele kernedumpen på, er det svært at komme til rødderne på et objekt, der ikke får GC-ed.

I skrivende stund kunne vi ikke finde noget værktøj online, der kan hjælpe os med det. Da der findes et kernedumpformat og en enkel nok måde at eksportere det fra debug-pakken, kan det være, at der er et, der bruges hos Google. Når man søger online ser det ud som om det er i Golang-pipelinen, hvilket skaber en kernedump-seer af sådan, men ser ikke ud til at nogen arbejder på det. Når det er sagt, selv uden adgang til en sådan løsning, med de eksisterende værktøjer kan vi normalt komme til grundårsagen.

Hukommelseslækager

Hukommelseslækage eller hukommelsestryk kan forekomme i mange former i hele systemet. Normalt adresserer vi dem som bugs, men nogle gange kan deres grundårsag være i designbeslutninger.

Når vi bygger vores system under nye designprincipper, antages sådanne overvejelser ikke at være vigtige, og det er okay. Det er vigtigere at opbygge systemet på en måde, der undgår for tidlige optimeringer og giver dig mulighed for at udføre dem senere, når koden modnes, snarere end at overkonstruere det fra starten. Der er stadig nogle almindelige eksempler på at se problemer med hukommelsestryk realisere sig:

  • For mange tildelinger, forkert datarepræsentation
  • Kraftig brug af refleksion eller strenge
  • Brug af globaler
  • Forældreløse, uendelige goroutines

I Go er den enkleste måde at oprette en hukommelseslækage på at definere en global variabel, array og tilføje data til det array. Dette fantastiske blogindlæg beskriver denne sag på en god måde.

Så hvorfor skriver jeg dette indlæg? Da jeg undersøgte denne sag, fandt jeg mange ressourcer om hukommelseslækage. Alligevel har systemer i virkeligheden mere end 50 linjer kode og en enkelt struktur. I sådanne tilfælde er det meget mere komplekst at finde kilden til et hukommelsesproblem, end hvad eksemplet beskriver.

Golang giver os et fantastisk værktøj kaldet pprof. Dette værktøj, når det er mestret, kan hjælpe med at undersøge og sandsynligvis finde ethvert hukommelsesproblem. Et andet formål det har er at undersøge CPU-problemer, men jeg vil ikke gå ind på noget relateret til CPU i dette indlæg.

gå værktøj pprof

At dække alt, hvad dette værktøj gør, kræver mere end et blogindlæg. En ting, der tog et stykke tid, er at finde ud af, hvordan man bruger dette værktøj til at få noget handlingsfrit. Jeg vil koncentrere dette indlæg om det hukommelsesrelaterede træk ved det.

Den pprofpakke skaber en bunke samplet dump fil, som du senere kan analysere / visualisere at give dig et kort over både:

  • Aktuelle hukommelsesallokeringer
  • I alt (kumulativ) allokering af hukommelse

Værktøjet har evnen til at sammenligne snapshots. Dette kan give dig mulighed for at sammenligne en tidsforskelvisning af hvad der skete lige nu og for eksempel for 30 sekunder siden. I stressscenarier kan dette være nyttigt at hjælpe med at finde problematiske områder i din kode.

pprof profiler

Den måde, pprof fungerer på, er at bruge profiler.

En profil er en samling af stakspor, der viser opkaldssekvenserne, der førte til forekomster af en bestemt begivenhed, såsom tildeling.

Filen runtime / pprof / pprof.go indeholder detaljeret information og implementering af profilerne.

Go har flere indbyggede profiler, som vi kan bruge i almindelige tilfælde:

  • goroutine - stak spor af alle aktuelle goroutines
  • heap - et stikprøve af hukommelsestildeling af levende objekter
  • allokeringer - en prøveudtagning af alle tidligere hukommelsesallokeringer
  • threadcreate - stak spor, der førte til oprettelsen af ​​nye OS-tråde
  • blok - stak spor, der førte til blokering af synkroniseringsprimitiver
  • mutex - stak spor af indehavere af modstridte mutexer

Når vi ser på hukommelsesproblemer, vil vi koncentrere os om bunkeprofilen. Tildelingsprofilen er identisk med hensyn til den dataindsamling, den gør. Forskellen mellem de to er den måde, som pprof-værktøjet læser der på starttidspunktet. Allocs- profilen starter pprof i en tilstand, der viser det samlede antal tildelte byte, siden programmet startede (inklusive affaldsindsamlede bytes). Vi bruger normalt denne tilstand, når vi prøver at gøre vores kode mere effektiv.

Bunken

Sammendrag er det her OS (operativsystem) gemmer hukommelsen af ​​objekter, som vores kode bruger. Dette er hukommelsen, som senere bliver 'skrald indsamlet' eller frigøres manuelt på ikke-skrald indsamlede sprog.

Bunken er ikke det eneste sted, hvor hukommelsesallokeringer sker, noget hukommelse tildeles også i stakken. Stakformålet er kortvarigt. I Go bruges stakken normalt til opgaver, der sker inden for lukningen af ​​en funktion. Et andet sted, hvor Go bruger stakken, er når compileren 'ved', hvor meget hukommelse der skal reserveres inden kørselstid (f.eks. Arrays med fast størrelse). Der er en måde at køre Go-kompilatoren på, så den udsender en analyse af, hvor allokeringer 'undslipper' stakken til bunken, men jeg vil ikke røre ved det i dette indlæg.

Mens bunke-data skal 'frigøres' og gc-ed, er stack-data ikke. Det betyder, at det er meget mere effektivt at bruge stakken, hvor det er muligt.

Dette er et abstrakt af de forskellige placeringer, hvor hukommelsestildeling sker. Der er meget mere, men dette vil være uden for rammerne for dette indlæg.

Indhentning af dyngedata med pprof

Der er to hovedmåder at få data til dette værktøj. Den første vil normalt være en del af en test eller en gren og inkluderer import runtime/pprofog derefter opkald for pprof.WriteHeapProfile(some_file)at skrive bunkeoplysningerne.

Bemærk, at det WriteHeapProfileer syntaktisk sukker til løb:

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

Ifølge dokumenterne WriteHeapProfilefindes der bagudkompatibilitet. Resten af ​​profilerne har ikke sådanne genveje, og du skal bruge Lookup()funktionen til at få deres profildata.

Den anden, som er den mere interessante, er at aktivere den via HTTP (webbaserede slutpunkter). Dette giver dig mulighed for at udtrække data adhoc fra en kørende container i dit e2e / testmiljø eller endda fra 'produktion'. Dette er endnu et sted, hvor Go-runtime og værktøjssæt udmærker sig. Hele pakkedokumentationen findes her, men TL; DR er, at du bliver nødt til at tilføje den til din kode som sådan:

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

' net/http/pprofBivirkningen ' ved import er den registrering, som pprof-slutpunkterne ligger under webserverens rod /debug/pprof. Nu ved hjælp af curl kan vi få bunkeinformationsfilerne til at undersøge:

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

Tilføjelse af http.ListenAndServe()ovenstående er kun påkrævet, hvis dit program ikke havde en http-lytter før. Hvis du har en, hænger den fast, og der er ikke behov for at lytte igen. Der er også måder at indstille det på ved hjælp af et ServeMux.HandleFunc()hvilket ville give mere mening for et mere komplekst http-aktiveret program.

Brug af pprof

Så vi har samlet dataene, hvad nu? Som nævnt ovenfor er der to hovedhukommelsesanalysestrategier med pprof. Den ene er omkring og ser på de aktuelle allokeringer (bytes eller objektantal), kaldet inuse. Den anden ser på alle de tildelte bytes eller objektantal i løbet af programmets kørselstid, kaldet alloc. Dette betyder, uanset om det var gc-ed, en sammenfatning af alt, hvad der blev samplet.

Dette er et godt sted at gentage, at bunkeprofilen er et stikprøve af hukommelsestildelinger . pprofbag kulisserne bruger runtime.MemProfilefunktionen, der som standard samler allokeringsoplysninger på hver 512 KB tildelte bytes. Det er muligt at ændre MemProfile for at indsamle oplysninger om alle objekter. Bemærk, at dette sandsynligvis vil bremse din ansøgning.

Dette betyder, at der som standard er en chance for, at der kan opstå et problem med mindre objekter, der glider under pprofs radar. For et stort codebase / langvarigt program er dette ikke et problem.

Når vi har samlet profilfilen, er det tid til at indlæse den i den interaktive konsol, pprof tilbyder. Gør det ved at løbe:

> go tool pprof heap.out

Lad os observere de viste oplysninger

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

Den vigtige ting at bemærke her er Type: inuse_space. Det betyder, at vi ser på tildelingsdata for et bestemt øjeblik (når vi fangede profilen). Typen er konfigurationsværdien af sample_index, og de mulige værdier er:

  • inuse_space - allokeret mængde hukommelse og endnu ikke frigivet
  • inuse_object s— mængden af ​​tildelte objekter og endnu ikke frigivet
  • alloc_space - samlet mængde allokeret hukommelse (uanset frigivet)
  • alloc_objects - samlet mængde tildelte objekter (uanset frigivet)

Indtast nu topdet interaktive, output vil være de største hukommelsesforbrugere

Vi kan se en linje, der fortæller os om Dropped Nodes, det betyder, at de er filtreret ud. En node er en objektindgang eller en 'node' i træet. At slippe noder er en god ide at reducere noget støj, men nogle gange kan det skjule grundårsagen til et hukommelsesproblem. Vi vil se et eksempel på det, når vi fortsætter vores undersøgelse.

Hvis du vil inkludere alle data i profilen, skal du tilføje -nodefraction=0indstillingen, når du kører pprof eller indtaste nodefraction=0det interaktive.

På den udsendte liste kan vi se to værdier, flatog cum.

  • flad betyder, at hukommelsen tildeles af denne funktion og holdes af denne funktion
  • cum betyder, at hukommelsen blev tildelt af denne funktion eller funktion, som den kaldte ned i stakken

Disse oplysninger alene kan nogle gange hjælpe os med at forstå, om der er et problem. Tag for eksempel et tilfælde, hvor en funktion er ansvarlig for at allokere en masse hukommelse, men ikke holder den. Dette ville betyde, at et andet objekt peger på den hukommelse og holder den allokeret, hvilket betyder, at vi muligvis har et systemdesignproblem eller en fejl.

Et andet pænt trick topi det interaktive vindue er, at det faktisk kører top10. Den øverste kommando understøtter topNformat, hvor Ner antallet af poster, du vil se. I det tilfælde, der er indsat ovenfor, ville indtastning af top70for eksempel output alle noder.

Visualiseringer

Mens det topNgiver en tekstliste, er der flere meget nyttige visualiseringsmuligheder, der kommer med pprof. Det er muligt at skrive pngeller gifmange andre (se go tool pprof -helpfor en komplet liste).

På vores system ser standard visuel output ud som:

Dette kan være skræmmende i starten, men det er visualiseringen af ​​hukommelsesallokeringsstrømme (ifølge stakkspor) i et program. At læse grafen er ikke så kompliceret som det ser ud. En hvid firkant med et tal viser tildelt plads (og kumulativet for, hvor meget hukommelse det tager lige nu på kanten af ​​grafen), og hvert bredere rektangel viser tildelingsfunktionen.

Bemærk, at jeg i ovenstående billede tog en png fra en inuse_spaceeksekveringstilstand. Mange gange skal du også se på inuse_objectsdet, da det kan hjælpe med at finde tildelingsproblemer.

Grave dybere, finde en grundlæggende årsag

Indtil videre var vi i stand til at forstå, hvad der tildeler hukommelse i vores applikation under løbetid. Dette hjælper os med at få en fornemmelse af, hvordan vores program opfører sig (eller opfører sig dårligt).

I vores tilfælde kunne vi se, at hukommelsen bevares af membuffers, hvilket er vores dataserialiseringsbibliotek. Dette betyder ikke, at vi har en hukommelseslækage ved det kodesegment, det betyder, at hukommelsen bevares af den funktion. Det er vigtigt at forstå, hvordan man læser grafen og pprof-output generelt. I dette tilfælde forstå, at når vi serieliserer data, hvilket betyder at vi tildeler hukommelse til strukturer og primitive objekter (int, streng), frigives de aldrig.

Hvis vi springer til konklusioner eller fejlagtigt fortolker grafen, kunne vi have antaget, at en af ​​noderne på stien til serialisering er ansvarlig for at bevare hukommelsen, for eksempel:

Et eller andet sted i kæden kan vi se vores loggningsbibliotek, der er ansvarlig for> 50 MB allokeret hukommelse. Dette er hukommelse, der tildeles af funktioner, der kaldes af vores logger. Når man tænker igennem, forventes dette faktisk. Loggeren forårsager hukommelsesallokeringer, da den har brug for at serialisere data for at udsende dem til loggen, og det forårsager således hukommelsestildelinger i processen.

Vi kan også se, at nede i allokeringsstien bevares hukommelsen kun ved serialisering og intet andet. Derudover er mængden af ​​hukommelse, der tilbageholdes af loggeren, ca. 30% af det samlede antal. Ovenstående fortæller os, at problemet sandsynligvis ikke er med loggeren. Hvis det var 100% eller noget tæt på det, skulle vi have kigget der - men det er det ikke. Hvad det kan betyde er, at der logges noget, der ikke burde være, men det er ikke en hukommelseslækage fra loggeren.

Dette er et godt tidspunkt at introducere en anden pprofkommando kaldet list. Det accepterer et regulært udtryk, som vil være et filter på, hvad der skal vises. 'Listen' er faktisk den kommenterede kildekode, der er relateret til tildelingen. I forbindelse med den logger, som vi ser på, udfører list RequestNewvi, som vi gerne vil se de opkald, der foretages til loggeren. Disse opkald kommer fra to funktioner, som tilfældigvis begynder med det samme præfiks.

Vi kan se, at de foretagne tildelinger sidder i cumkolonnen, hvilket betyder, at den tildelte hukommelse bevares nede i opkaldstakken. Dette korrelerer med, hvad grafen også viser. På det tidspunkt er det let at se, at årsagen til, at loggeren tildelte hukommelsen, er, at vi sendte det hele 'blok'-objektet. Det var i det mindste nødvendigt at serieisere nogle dele af det (vores objekter er membufferobjekter, som altid implementerer en eller anden String()funktion). Er det en nyttig logmeddelelse eller god praksis? Sandsynligvis ikke, men det er ikke en hukommelseslækage, ikke i loggerenden eller den kode, der kaldte loggeren.

listkan finde kildekoden, når du søger efter den under dit GOPATHmiljø. I tilfælde hvor roden, den søger efter, ikke stemmer overens, hvilket afhænger af din byggemaskine, kan du bruge -trim_pathindstillingen. Dette hjælper med at rette det og lade dig se den kommenterede kildekode. Husk at indstille din git til den rette forpligtelse, som kørte, da bunkeprofilen blev fanget.

Så hvorfor bevares hukommelsen?

Baggrunden for denne undersøgelse var mistanken om, at vi har et problem - en hukommelseslækage. Vi kom til denne opfattelse, da vi så hukommelsesforbruget var højere end hvad vi ville forvente, at systemet havde brug for. Oven i det så vi det stadig øge, hvilket var en anden stærk indikator for 'der er et problem her'.

På dette tidspunkt, i tilfælde af Java eller .Net, åbner vi nogle 'gc roots' analyser eller profiler og kommer til det faktiske objekt, der henviser til disse data, og skaber lækagen. Som forklaret er dette ikke nøjagtigt muligt med Go, både på grund af et værktøjsproblem, men også på grund af Go's lave hukommelsesrepræsentation.

Uden at gå i detaljer, tror vi ikke, at Go bevarer, hvilket objekt der er gemt på hvilken adresse (undtagen måske markører). Dette betyder, at forståelse af, hvilken hukommelsesadresse der repræsenterer hvilket medlem af dit objekt (struct), faktisk kræver en slags kortlægning til output af en bunkeprofil. Talteori, dette kan betyde, at inden man tager en fuld kernedump, skal man også tage en bunkeprofil, så adresserne kan kortlægges til den allokerende linje og fil og dermed det objekt, der er repræsenteret i hukommelsen.

På dette tidspunkt, fordi vi er fortrolige med vores system, var det let at forstå, at dette ikke længere er en fejl. Det var (næsten) af design. Men lad os fortsætte med at undersøge, hvordan man får oplysningerne fra værktøjerne (pprof) til at finde årsagen.

Ved indstilling får nodefraction=0vi vist hele kortet over de tildelte objekter, inklusive de mindre. Lad os se på output:

Vi har to nye undertrær. Påminder igen, pprof heap-profil prøver hukommelsestildelinger. For vores system, der fungerer - mangler vi ikke vigtige oplysninger. Det længere nye træ, i grønt, der er helt afbrudt fra resten af ​​systemet, er testløber, det er ikke interessant.

Den kortere i blå, som har en kant, der forbinder den med hele systemet er inMemoryBlockPersistance. Dette navn forklarer også den 'lækage', vi forestillede os, at vi har. Dette er data-backend, som lagrer alle data i hukommelsen og ikke fortsætter til disken. Hvad der er rart at bemærke er, at vi straks kunne se, at det holder to store genstande. Hvorfor to? Fordi vi kan se, er objektet på størrelse 1,28MB, og funktionen bevarer 2,57MB, hvilket betyder to af dem.

Problemet er godt forstået på dette tidspunkt. Vi kunne have brugt delve (fejlfindingsprogrammet) til at se, at dette er det array, der indeholder alle blokke for den in-memory persistens-driver, vi har.

Så hvad kunne vi ordne?

Nå, det sugede, det var en menneskelig fejl. Mens processen var uddannelse (og deling er omsorgsfuld), blev vi ikke bedre, eller gjorde vi?

Der var en ting, der stadig 'lugtede' ved denne bunkeinformation. De deserialiserede data tog for meget hukommelse, hvorfor 142MB til noget, der skulle tage væsentligt mindre? . . pprof kan svare på det - faktisk eksisterer det at besvare sådanne spørgsmål nøjagtigt.

For at se på den kommenterede kildekode for funktionen kører vi list lazy. Vi bruger lazy, da funktionsnavnet vi leder efter er, lazyCalcOffsets()og vi kender ingen andre funktioner i vores kode, der begynder med doven. At skrive list lazyCalcOffsetsville også fungere selvfølgelig.

Vi kan se to interessante informationer. Husk igen, at pprof-bunkeprofilen prøver information om tildelinger. Vi kan se, at både flatog cumtallene er de samme. Dette indikerer, at den tildelte hukommelse også bevares af disse tildelingspunkter.

Dernæst kan vi se, at mærket () tager noget hukommelse. Det giver mening, det er markøren til datastrukturen. Alligevel ser vi også, at opgaven på linje 43 optager hukommelse, hvilket betyder, at den skaber en allokering.

Dette lærte os om kort, hvor en opgave til et kort ikke er en ligetil variabel tildeling. Denne artikel går i detaljer om, hvordan kort fungerer. Kort sagt har et kort et overhead, og jo flere elementer, jo større vil denne omkostning 'koste', når man sammenligner med et udsnit.

Følgende skal tages med et saltkorn: Det ville være okay at sige, at brug af a map[int]T, når dataene ikke er sparsomme eller kan konverteres til sekventielle indekser, normalt skal forsøges med en skiveimplementering, hvis hukommelsesforbrug er en relevant overvejelse . Alligevel kan en stor skive, når den udvides, muligvis bremse en operation, hvor denne afmatning på et kort vil være ubetydelig. Der er ingen magisk formel for optimeringer.

I koden ovenfor, efter at have kontrolleret, hvordan vi brugte kortet, indså vi, at mens vi forestillede os, at det var et sparsomt array, kom det ud som ikke så sparsomt. Dette svarer til ovenstående argument, og vi kunne straks se, at en lille refaktor for at ændre kortet til en skive faktisk er mulig og muligvis gøre denne kode mere hukommelseseffektiv. Så vi ændrede det til:

Så simpelt som det, i stedet for at bruge et kort bruger vi nu et udsnit. På grund af den måde, hvorpå vi modtager de data, der er doven indlæst i det, og hvordan vi senere får adgang til disse data, bortset fra disse to linjer, og strukturen, der indeholder disse data, var der ikke behov for anden kodeændring. Hvad gjorde det med hukommelsesforbruget?

Lad os se på det benchcmpfor et par tests

Læsetestene initialiserer datastrukturen, hvilket opretter allokeringerne. Vi kan se, at runtime forbedres med ~ 30%, allokeringer er nede med 50% og hukommelsesforbrug med> 90% (!)

Da kortet, nu-skive, aldrig blev fyldt med mange ting, viser tallene stort set hvad vi vil se i produktionen. Det afhænger af dataentropien, men der kan være tilfælde, hvor både allokeringer og forbedringer af hukommelsesforbruget ville have været endnu større.

Ser vi pprofigen og tager en bunkeprofil fra samme test, vil vi se, at hukommelsesforbruget nu faktisk er nede med ~ 90%.

Takeaway vil være, at for mindre datasæt skal du ikke bruge kort, hvor skiver ville være tilstrækkelige, da kort har en stor overhead.

Fuld kernedump

Som nævnt er det her, vi ser den største begrænsning med værktøj lige nu. Da vi undersøgte dette spørgsmål, blev vi besat af at kunne komme til rodobjektet uden meget succes. Go udvikler sig over tid i et stort tempo, men denne udvikling kommer med en pris i tilfælde af fuld dump eller hukommelsesrepræsentation. Det fulde heap dump-format, når det ændres, er ikke bagudkompatibelt. Den seneste version, der er beskrevet her, og for at skrive en fuld bunke dump, kan du bruge debug.WriteHeapDump().

Omend lige nu finder vi os ikke 'fast', fordi der ikke er nogen god løsning til at udforske fulde lossepladser. pprofbesvaret alle vores spørgsmål indtil nu.

Bemærk, at Internettet husker en masse information, som ikke længere er relevant. Her er nogle ting, du bør ignorere, hvis du selv vil prøve at åbne en fuld dump, fra og med go1.11:

  • Der er ingen måde at åbne og debugge en fuld kernedump på MacOS, kun Linux.
  • Værktøjerne på //github.com/randall77/hprof er til Go1.3, der findes en gaffel til 1.7+, men den fungerer heller ikke ordentligt (ufuldstændig).
  • viewcore på //github.com/golang/debug/tree/master/cmd/viewcore kompilerer ikke rigtig. Det er let nok at rette (pakker internt peger på golang.org og ikke github.com), men det fungerer heller ikke , ikke på MacOS, måske på Linux.
  • Også //github.com/randall77/corelib mislykkes på MacOS

pprof UI

En sidste detalje at være opmærksom på, når det kommer til pprof, er dens UI-funktion. Det kan spare meget tid, når der påbegyndes en undersøgelse af ethvert spørgsmål, der vedrører en profil taget med pprof.

go tool pprof -http=:8080 heap.out

På det tidspunkt skal den åbne webbrowseren. Hvis det ikke gør det, skal du søge til den port, du indstiller den til. Det giver dig mulighed for at ændre indstillingerne og få den visuelle feedback meget hurtigere end du kan fra kommandolinjen. En meget nyttig måde at forbruge informationen på.

Brugergrænsefladen fik mig faktisk til at kende flammegraferne, som udsætter skyldige områder af koden meget hurtigt.

Konklusion

Go er et spændende sprog med et meget rigt værktøjssæt, der er meget mere du kan gøre med pprof. Dette indlæg berører f.eks. Slet ikke CPU-profilering.

Nogle andre gode læser:

  • //rakyll.org/archive/ - Jeg mener, at dette er en af ​​go bidragsydere omkring ydeevneovervågning, mange gode indlæg på hendes blog
  • //github.com/google/gops - skrevet af JBD (som kører rakyll.org), dette værktøj garanterer sit eget blogindlæg.
  • //medium.com/@cep21/using-go-1-10-new-trace-features-to-debug-an-integration-test-1dc39e4e812d - go tool tracesom er omkring CPU-profilering, dette er et godt indlæg om den profileringsfunktion .