Muistivuodon metsästys Python-sovelluksissa

Wai Chee Yau

Seuraa

13. helmikuuta, 2019 – 4 min read

Käyttelemme Pythonia melko paljon Zendeskin palvelimella, kun rakennamme koneenoppimis- (ML-) tuotteita. Yksi yleisimmistä suorituskykyongelmista, joihin törmäsimme koneoppimissovellusten kanssa, on muistivuodot ja -piikit. Python-koodi suoritetaan yleensä konteissa hajautettujen käsittelykehysten, kuten Hadoopin, Sparkin ja AWS Batchin, kautta. Jokaiselle kontille varataan kiinteä määrä muistia. Kun koodin suoritus ylittää määritellyn muistirajan, kontti lopetetaan muistin loppumiseen liittyvien virheiden vuoksi.

Pikaratkaisu on lisätä muistin varausta. Tämä voi kuitenkin johtaa resurssien tuhlaamiseen ja vaikuttaa tuotteiden vakauteen arvaamattomien muistipiikkien vuoksi. Muistivuodon syitä voivat olla muun muassa:

  • suurten objektien sitominen, joita ei vapauteta
  • viittaussyklit koodissa
  • koodin taustalla olevat kirjastot/C-laajennukset, jotka vuotavat muistia

Hyödyllinen harjoitus on profiloida sovellusten muistinkäyttö, jotta saadaan parempi käsitys koodin ja sen taustalla olevien käytettävien pakettien tilatehokkuudesta. Tässä postauksessa käsitellään:

  • sovelluksen muistinkäytön profilointi ajassa
  • miten tarkastellaan muistinkäyttöä ohjelman tietyssä osassa
  • vinkkejä muistiongelmien vianmääritykseen

Muistiprofiilipaketin avulla voit tarkastella muistinkäytön vaihtelua ajassa Python-koodin suorituksen aikana.

# install the required packages
pip install memory_profiler
pip install matplotlib# run the profiler to record the memory usage
# sample 0.1s by defaut
mprof run --include-children python fantastic_model_building_code.py# plot the recorded memory usage
mprof plot --output memory-profile.png

A. Muistiprofiili ajan funktiona

Vaihtoehto include-children sisältää kaikkien emoprosessin kautta poikineiden lapsiprosessien muistinkäytön. Kuvaajassa A näkyy iteratiivinen mallin koulutusprosessi, joka aiheuttaa muistin lisääntymisen sykleittäin, kun koulutusdatan eriä käsitellään. Objektit vapautetaan, kun roskienkeräys käynnistyy.

Jos muistin käyttö kasvaa jatkuvasti, on olemassa mahdollinen ongelma muistivuodoista. Tässä on tyhmä esimerkkiskripti havainnollistamaan tätä.

B. Muistijäljet kasvavat ajan mittaan

Vianmäärityksen taukopiste voidaan asettaa, kun muistin käyttö ylittää tietyn kynnysarvon, käyttämällä optiota pdb-mmem, joka on kätevä vianmäärityksessä.

Muistityhjennys tiettynä ajankohtana

On tärkeää ymmärtää ohjelmassa olevien suurten objektien odotettavissa oleva määrä ja se, pitäisikö niitä monistaa ja/tai muuntaa eri muotoihin.

Muistissa olevien objektien tarkemmaksi analysoimiseksi voidaan muppy-ohjelmalla luoda heap-dumppi tiettyjen ohjelmakoodirivien aikana.

Esimerkki yhteenvedosta muistin kasan dumppauspisteestä

Toinen hyödyllinen muistin profiloinnin mahdollistava kirjasto on objgraph, joka voi luoda objektien grafiikoita, joiden avulla voidaan tarkastaa objektien linjat.

Pyrkimys nopeaan palautesilmukkaan

Hyödyllinen lähestymistapa on pienen ”testitapauksen” luominen, jossa ajetaan vain kyseistä muistivuotokoodia. Harkitse osajoukon käyttämistä satunnaisesti poimitusta datasta, jos koko syötedatan ajaminen on pitkäkestoista.

Käynnistä muistia vaativat tehtävät erillisessä prosessissa

Python ei välttämättä vapauta muistia heti takaisin käyttöjärjestelmälle. Jotta voidaan varmistaa, että muisti vapautuu koodin suorituksen jälkeen, sitä on ajettava erillisessä prosessissa. Tällä sivulla on lisätietoja Pythonin roskienkeruusta.

Debuggeri voi lisätä viittauksia objekteihin

Jos käytetään breakpoint-debuggeria, kuten pdb:tä, kaikki objekteja, jotka on luotu ja joihin viitataan manuaalisesti debuggerista, jäävät muistiprofiiliin. Tämä voi luoda vääränlaisen tunteen muistivuodoista, jolloin objekteja ei vapauteta ajoissa.

Varo paketteja, jotka voivat olla vuotavia

Joissain Python-kirjastoissa voi mahdollisesti olla muistivuotoja. Esim. pandasilla on melko paljon tunnettuja muistivuoto-ongelmia.

Hyvää metsästystä!

Vastaa

Sähköpostiosoitettasi ei julkaista.