pprof in golang: correction d'une fuite de mémoire

À de rares exceptions près ( un , deux << l' original est moins bien formaté, l'OMI ) les articles sur le «profilage» dans golang sont une réimpression de l'annotation du paquet pprof (pas même cet ancien article ) et ensuite une petite expérience personnelle sur la façon dont (non) réussi avec l'aide pprof trouve le problème.





Nuancer

, google "" "" . "" "" "golang pprof" - . , .





, "" . - / , , () . " ", .





: "" - "". ( , .) ( ) " ", ( " ") 20+.





" " - " ". ( ) . , "", "". , " " . "". " " .





  • . , , ( ) "" go. - , goroutines …









, - ́ "pprof.WriteHeapProfile()". : " " "" 512. ( "").





"́ ": "WriteTo()" "" "debug=2":





pprof.Lookup("heap").WriteTo(some_file, 2)
      
      



pprof, . , " " .





  • , "net/http/pprof" curl/wget. , : "http.ListenAndServe()" , . .. "ListenAndServe()" . "go …" goroutine.





pprof ( ). .





1. HeapProfile

import (
	"runtime"
	"runtime/pprof"
)
// Debug: pprof.WriteHeapProfile()
				memprofile := "/run/dnsd/memprofile"
				f, _ := os.Create(memprofile)
				runtime.GC() // get up-to-date statistics
				pprof.WriteHeapProfile(f)
				f.Close()
// Debug: pprof http listener
//	go http.ListenAndServe("localhost:8080", nil)
      
      



  • , . — curl.





2.

( 512 4…6 ), 99% .





goroutine "main.apiCall.func1()" 10923 "". (, .. "" 512 . - …)





# go tool pprof -nodefraction=0 -inuse_objects memprofile.3+
File: dnsd
Type: inuse_objects
Time: Dec 24, 2020 at 10:38am (MSK)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 19387, 100% of 19387 total
Showing top 10 nodes out of 32
      flat  flat%   sum%        cum   cum%
     10923 56.34% 56.34%      10923 56.34%  main.apiCall.func1
      8192 42.26% 98.60%       8192 42.26%  regexp.mergeRuneSets.func2
       256  1.32% 99.92%        256  1.32%  bufio.NewWriterSize
        16 0.083%   100%         16 0.083%  compress/flate.(*dictDecoder).init
      
      



3. /

:





	// To complete report processing even after return on timeout
	go func () {
		defer report.DelNotifier(commands.UUID)

		signals := make(chan os.Signal, 1)
		signal.Notify(signals, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
		for {
			select {
			case index := <-callback:
				if (index + 1) >= len(Workers) {
					done <- struct{}{}
					return
				}
			case t:= <- timer: // t++ on each tick, t=-1 at the end
				if t > 0 {
					xl.Warn("apiCall: Timer tick while still not enough reports from workers!")
				}
				if t < 0 { // Time is over
					xl.Err("apiCall: Time over while still not enough reports from workers!")
					err = fmt.Errorf("Time over")
					done <- struct{}{}
					return
				}
			case exitSignal = <-signals:
				xl.Warnf("apiCall: Interrupt is detected: %s", exitSignal)
				xl.Warn("apiCall: Waiting for timeout to complete report processing...")
				err = fmt.Errorf("Interrupt")
				done <- struct{}{}
				return
			}
		}
	} ()
      
      



4.

, "" "commands.UUID" (commands "" ). , .. "" defer. , . - . - :





go func (uuid string) {
} (commands.UUID)
      
      



SIGKILL (""), . , - - .





, "". - ? :





		signal.Notify(signals, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
      
      



, "defer report.DelNotifier()" . "signal.Notify()" , . , "os.Signal" " " . . , , " ".





, , " ". "" , "" — .





5. Happy end

:





defer signal.Stop(signals)
      
      



, :





# go tool pprof -nodefraction=0 -inuse_objects memprofile.1
File: dnsd
Type: inuse_objects
Time: Dec 25, 2020 at 11:56am (MSK)
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 0, 0% of 0 total
      flat  flat%   sum%        cum   cum%
      
      



() . . " " .





.





, "" ( ""). () , .. "" ( "" ).





golang, , " ". ( ) :





  • . ( " ") "", . — …





  • "" goroutine ( "" ).





  • "defer …" ( - goroutine, ).





  • "" ( "signal.Notify()") .





go1.14. 1.8. 1.8 30 . .





J'ai dû m'abstenir d'essayer go1.15. Parce que les hipsters qui se sont faufilés ont cassé le support X.509 "CommonName" lors de la vérification des certificats. (Traditionnellement) ne sachant pas qu'en dehors de l'Internet public, il existe toutes sortes de segments «fermés», avec des délais élevés pour apporter des changements.





Voilà donc tout.





La critique constructive et le pointage du doigt «où suis-je un imbécile» sont les bienvenus.





Profitant de cette opportunité, tout le monde avec l'année à venir 2021!








All Articles