- spectacle
- solutions
- Processus d'orientation
spectacle
Environnement d'exploitation:
# uname -a
Linux ** 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
# python2 --version
Python 2.7.5
# cat /etc/*-release
CentOS Linux release 7.2.1511 (Core)
programme de python après une longue période de temps (une plus grande charge) en cours d'exécution pendant un certain temps, la mémoire de python pour les processus du système continue à augmenter:
# ps aux | grep python2
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 124910 10.2 0.8 5232084 290952 ? Sl Mar17 220:37 python2 offline.py restart
# ~~~~~~
# 290M 内存占用
processus ici python grand nombre de demandes en cours de traitement, la mémoire continue d'augmenter, mais après la chute de pression de charge finale, et ne laissez pas tomber une mémoire.
solutions
Pour gagner du temps au lecteur, cette conclusion est donnée en premier, suivi par les étapes de dépannage détaillées de réenregistrement.
Nous progressivement en plusieurs étapes pour localiser le problème:
- Tout d'abord, de déterminer ce que le programme a été fait, qu'il y ait un comportement anormal.
- Après l'exclusion d'un comportement anormal, utilisation de la mémoire pour voir le python, si tous les objets récupérés ont été récupérés.
- Après avoir retiré le problème de fuite de mémoire dans le python de collecte des ordures, accédez au problème de la mise en œuvre libc malloc.
La solution finale est très simple, remplacement direct pour le module malloc tcmalloc:
LD_PRELOAD="/usr/lib64/libtcmalloc.so" python x.py
Processus d'orientation
gdb-python: programme python pour savoir ce qu'il faut faire
Il faut d'abord déterminer ce python fait, n'est pas une tâche importante de la consommation de mémoire normale est en cours d'exécution, blocage de comportement anormal.
Cet aspect peut être utilisé pour aider gdb, du gdb-7 départ, le soutien gdb gdb en python pour réaliser l'expansion. Comme on peut le programme de mise au point c, vérifier avec gdb pour les fils de python, pile d'appel et ainsi de suite.
Et vous pouvez appeler pile code c à l' intérieur du code python et imprimer en même temps .
Une telle incertitude est un problème de code python ou question son code sous-jacent c quand utile.
Les étapes détaillées peuvent être appelées débogage avec GDB .
prêt gdb
Tout d'abord, installez le python debuginfo:
# debuginfo-install python-2.7.5-39.el7_2.x86_64
Dans le debuginfo d'absence, en cours d'exécution gdb pas en arrière sera rapide blabla, suivez les instructions pour poursuivre l'installation, etc.:
Missing separate debuginfos, use: debuginfo-install python-2.7.5-39.el7_2.x86_64
accès gdb
Ensuite, nous pouvons utiliser gdb attacher directement à un processus de python pour voir son état de fonctionnement:
# gdb python 11122
Après avoir entré joindre une gdb, vous pouvez faire plus de quelques étapes de base pour vérifier:
Afficher le fil
(gdb) info threads
Id Target Id Frame
206 Thread 0x7febdbfe3700 (LWP 124916) "python2" 0x00007febe9b75413 in select () at ../sysdeps/unix/syscall-template.S:81
205 Thread 0x7febdb7e2700 (LWP 124917) "python2" 0x00007febe9b75413 in select () at ../sysdeps/unix/syscall-template.S:81
204 Thread 0x7febdafe1700 (LWP 124918) "python2" 0x00007febe9b75413 in select () at ../sysdeps/unix/syscall-template.S:81
203 Thread 0x7febda7e0700 (LWP 124919) "python2" 0x00007febe9b7369d in poll () at ../sysdeps/unix/syscall-template.S:81
blocage de verrouillage général presque peut voir ici, il y a un fil coincé dans la fonction xx_wait comme.
Avant d'utiliser cette méthode de localisation d'un module d'enregistrement de python en raison de l'exécution dans une fourchette de processus multithread, ce qui après verrouillage de l'enregistrement est verrouillé à nouveau processus fourche, mais le fil ne fourche pas débloquer de nouveaux processus a provoqué la mort problème de verrouillage.
En regardant la pile d'appel
Si vous rencontrez un problème avec un fil, le commutateur de fil pour afficher la pile d'appel pour déterminer les étapes de mise en œuvre spécifique, utilisez la bt
commande suivante :
(gdb) bt
#16 0x00007febea8500bd in PyEval_EvalCodeEx (co=<optimized out>, globals=<optimized out>, locals=locals@entry=0x0, args=<optimized out>,
argcount=argcount@entry=1, kws=0x38aa668, kwcount=2, defs=0x3282a88, defcount=2, closure=closure@entry=0x0)
at /usr/src/debug/Python-2.7.5/Python/ceval.c:3330
...
#19 PyEval_EvalFrameEx (
f=f@entry=Frame 0x38aa4d0, for file t.py, line 647, in run (part_num=2, consumer=<...
bt
Commande c peut non seulement voir la pile d'appel, mais montre aussi la source de python de pile d'appel, comme ci-dessus, c est le cadre 16, le cadre-19 a montré un code source python qui les correspond à une ligne.
Si vous ne voyez le code de la pile d'appel en python utilisant py-bt
la commande suivante :
(gdb) py-bt
#1 <built-in method poll of select.epoll object at remote 0x7febeacc5930>
#3 Frame 0x3952450, for file /usr/lib64/python2.7/site-packages/twisted/internet/epollreactor.py, line 379, in doPoll (self=<...
l = self._poller.poll(timeout, len(self._selectables))
#7 Frame 0x39502a0, for file /usr/lib64/python2.7/site-packages/twisted/internet/base.py, line 1204, in mainLoop (self=<...
py-bt
Indique le source de python de pile d'appel, paramètres d'appel et le code de la rangée.
coredump
Si vous voulez plus de temps tracking est préférable de traiter tout le programme python d'information sur Coredump, après que le fichier de base pour l'analyse pour ne pas affecter le déroulement du programme.
(gdb) generate-core-file
Cette commande vider le programme en cours gdb joindre au répertoire d'exécution, le nom core.<pid>
, et ensuite utiliser gdb charger le fichier de base, pile d'impression, l' analyse des variables de la montre, etc., sans avoir à attacher à un programme en cours d' exécution:
# gdb python core.<pid>
D'autres commandes
D' autres commandes peuvent être saisies dans gdb py<TAB><TAB>
voir, gdb et la commande correspondant, par exemple:
(gdb) py
py-bt py-list py-print python
py-down py-locals py-up python-interactive
py-up
,py-down
Il peut être utilisé pour passer à la précédente ou la gare d'appel python cadre.py-locals
Les variables locales utilisées pour imprimer
Et ainsi de suite et ainsi de suite peut également utiliser gdb en help
vue de la commande help:
(gdb) help py-print
Look up the given python variable name, and print it
Dans le processus de suivi avec gdb-python exclure le problème de la logique du programme, puis continuer à suivre les fuites de mémoire:
pyrasite: connexion dans le programme python
pyrasite est 1 peut se connecter directement un programme en cours d'exécution de python, ouvert ipython un terminal interactif similaire pour exécuter le programme pour vérifier l'état de la commande.
Cela nous donne débogueur offre une grande commodité. Tout simplement artefact.
Installation:
# pip install pyrasite
...
# pip show pyrasite
Name: pyrasite
Version: 2.0
Summary: Inject code into a running Python process
Home-page: http://pyrasite.com
Author: Luke Macken
...
Relié au programme en question, commencer à recueillir des informations:
pyrasite-shell <pid>
>>>
Ensuite , vous pouvez dans <pid>
le processus d'appel à un code python arbitraire pour voir l'état du processus.
Voici quelques petits ascenseur public (spéciale Ce que je méthode d'entrée moyenne outil ..) peut être utilisé pour afficher l'état de la mémoire dans le processus:
psutil afficher l'état du processus de python
pip install psutil
D'abord, regardez la quantité de processus mémoire système python RSS:
pyrasite-shell 11122
>>> import psutil, os
>>> psutil.Process(os.getpid()).memory_info().rss
29095232
commande Ps affiche les résultats de base et cohérente
rss La taille mémoire réelle (set résident) du procédé (à 1024 unités d'octet).
Guppy obtenir divers objets utilisation de la mémoire d'occupation
guppy peut être utilisé pour imprimer une variété d'objets chacun prennent beaucoup de place, s'il n'y a pas de libération cible de processus de python, entraînant l'empreinte mémoire accrue, vous pouvez vérifier par guppy:
De même, en suivant les étapes sont pyrasite-coquille, attacher au processus cible après l'opération.
# pip install guppy
from guppy import hpy
h = hpy()
h.heap()
# Partition of a set of 48477 objects. Total size = 3265516 bytes.
# Index Count % Size % Cumulative % Kind (class / dict of class)
# 0 25773 53 1612820 49 1612820 49 str
# 1 11699 24 483960 15 2096780 64 tuple
# 2 174 0 241584 7 2338364 72 dict of module
# 3 3478 7 222592 7 2560956 78 types.CodeType
# 4 3296 7 184576 6 2745532 84 function
# 5 401 1 175112 5 2920644 89 dict of class
# 6 108 0 81888 3 3002532 92 dict (no owner)
# 7 114 0 79632 2 3082164 94 dict of type
# 8 117 0 51336 2 3133500 96 type
# 9 667 1 24012 1 3157512 97 __builtin__.wrapper_descriptor
# <76 more rows. Type e.g. '_.more' to view.>
h.iso(1,[],{})
# Partition of a set of 3 objects. Total size = 176 bytes.
# Index Count % Size % Cumulative % Kind (class / dict of class)
# 0 1 33 136 77 136 77 dict (no owner)
# 1 1 33 28 16 164 93 list
# 2 1 33 12 7 176 100 int
A travers les étapes ci-dessus, vous pouvez voir que pas beaucoup d'objet python occupe plus de mémoire.
Les objets ne peuvent être récupérés
python lui-même est la collecte des ordures, mais la situation est en quelque sorte d'objets du programme python ne peut pas être ordures (objet irrécouvrable), remplir deux conditions:
- références circulaires
- Un objet de la chaîne définit une référence circulaire
__del__
procédé.
L'argument officiel est qu'un ensemble d'objets avec le module de références circulaires est identifié comme recyclable, mais vous devez faire appel à chaque objet des __del__
méthodes pour récupérer, mais définis par l' utilisateur des __del__
objets, le système gc ne sait pas appeler doit sonner qui , __del__
ne peut pas être récupéré. ces objets.
objets Python ne peuvent pas être recyclés continuera d'occuper la mémoire, quand on soupçonne qu'il ya un problème trouve ici qui ne peuvent pas être des objets recyclés cause de la mémoire continue d'augmenter.
Nous essayons donc de lister tous les objets ne peuvent pas être recyclés.
Ceci a été déterminé par la suite de ne pas les problèmes de mémoire causés par Autorisation non disponible. Ne peut pas être récupéré par un cours peut
gc.get_objects()
être inscrit, etgc.collect()
rejoindre après l'appel àgc.garbage
la liste. Mais ça ne nous a pas la présence de ces objets.
Trouvez les objets non recouvrables:
pyrasite-shell 11122
>>> import gc
>>> gc.collect() # first run gc, find out uncollectable object and put them in gc.garbage
# output number of object collected
>>> gc.garbage # print all uncollectable objects
[] # empty
Si vous imprimez la dernière étape ci - dessus tout objet qui ne peut être recyclé, nous devons examiner d' autres références circulaires sur la chaîne sur laquelle l' objet contient des __del__
méthodes.
Voici un exemple de la façon de générer ne pouvait récupérer l'objet:
Des exemples d'objets ne peuvent pas être récupérés?
from __future__ import print_function
import gc
'''
This snippet shows how to create a uncollectible object:
It is an object in a cycle reference chain, in which there is an object
with __del__ defined.
The simpliest is an object that refers to itself and with a __del__ defined.
> python uncollectible.py
======= collectible object =======
*** init, nr of referrers: 4
garbage: []
created: collectible: <__main__.One object at 0x102c01090>
nr of referrers: 5
delete:
*** __del__ called
*** after gc, nr of referrers: 4
garbage: []
======= uncollectible object =======
*** init, nr of referrers: 4
garbage: []
created: uncollectible: <__main__.One object at 0x102c01110>
nr of referrers: 5
delete:
*** after gc, nr of referrers: 5
garbage: [<__main__.One object at 0x102c01110>]
'''
def dd(*msg):
for m in msg:
print(m, end='')
print()
class One(object):
def __init__(self, collectible):
if collectible:
self.typ = 'collectible'
else:
self.typ = 'uncollectible'
# Make a reference to it self, to form a reference cycle.
# A reference cycle with __del__, makes it uncollectible.
self.me = self
def __del__(self):
dd('*** __del__ called')
def test_it(collectible):
dd()
dd('======= ', ('collectible' if collectible else 'uncollectible'), ' object =======')
dd()
gc.collect()
dd('*** init, nr of referrers: ', len(gc.get_referrers(One)))
dd(' garbage: ', gc.garbage)
one = One(collectible)
dd(' created: ', one.typ, ': ', one)
dd(' nr of referrers: ', len(gc.get_referrers(One)))
dd(' delete:')
del one
gc.collect()
dd('*** after gc, nr of referrers: ', len(gc.get_referrers(One)))
dd(' garbage: ', gc.garbage)
if __name__ == "__main__":
test_it(collectible=True)
test_it(collectible=False)
Le code ci - dessus crée deux objets, on peut être recyclé, on ne peut pas être recyclé, ils définissent les deux __del__
méthodes, la seule différence est que les références elles - mêmes (constituant ainsi un anneau de référence).
Si cette étape trouver une référence circulaire, il est nécessaire d'étudier plus ce qui a causé la relation entre la référence référence circulaire, puis détruit la référence circulaire, de sorte que devient l'objet peut être recyclé.
objgraph trouver une référence circulaire
# pip install objgraph
pyrasite-shell 11122
>>> import objgraph
>>> objgraph.show_refs([an_object], filename='sample-graph.png')
Dans l'exemple ci-dessus, une image sera générée localement, est décrit par le diagramme peut être référencé par an_object à:
Une référence spécifique: objgraph
Dans cette étape, on n'a pas trouvé l'objet ne peut être recyclé, et enfin nous soupçonnons que le problème de la glibc malloc quand utiliser tcmalloc après que le problème de malloc glibc alternative par défaut est fixé.
Archiver
- 9 janvier 2019 câble coaxial bon intervieweur Série-1: Comparaison de deux dict python (multi-niveaux) sont les mêmes
- 13 décembre 2018 l' exercice de dessin par jour, continuellement mis à jour
- 4 novembre 2018 stockées dans l'optimisation de la stratégie de fusion de fichiers
- 27 septembre 2018 Génie logiciel est un grille - pain
- 26 août 2018 programmeur doit être au courant des choses que la plupart des gens que je ne lui dis pas
- 2018 16 août cgexec pas Hériter variable d'environnement LD_PRELOAD
- 4 août 2018 MySQL groupe de réplication pratique: enregistrer les étapes, les questions et considérations
- 13 février 2018 énumère tous nombre entier de Pythagore
- 3 février 2018 différence dans le ansible comprennent, include_tasks et les import_tasks
- 2017 20 novembre fosse subprocess.Popen python concurrente
- 05 août 2017 programmeurs lecture obligatoire: découvrez le tempérament de table de hachage
- 6 mai 2017 Problèmes de mémoire de processus de croissance Python, des solutions et des outils
- 1 février 2017 XP série tutoriel système distribué: Erasure-Code: travaux, explication mathématique, la pratique et l' analyse.
- 1 février 2017 XP série tutoriel système distribué: Erasure-Code: travaux, explication mathématique, la pratique et l' analyse.
- 11 Nov 2015 des systèmes distribués fiables d'interprétation visuelle à base Paxos
- 28 juillet 2015 prise Fermer: fermer cette différence () et l' arrêt () de
- 17 mai 2015 changer facilement le monde git-auto-courge
- 17 fév 2015 Nombres Les programmeurs doivent savoir au sujet Hash
- 11 février 2015 Vim- TabBar: simple, stupide et TabBar rapide pour VIM
- 2014 Jul-24 . 1% plus lente demande d'optimisation
- 31 janv 2014 Quelques ressources utiles
- 31 janvier 2014 jobq.py - moteur de traitement de file d' attente