Résumé du bug
Lançant ma série de compilations avec latexmk, j’obtiens, à la deuxième compilation XeLaTeX, le message suivant :
TeX capacity exceeded, sorry [main memory size=5000000]
D’habitude, ce type de message est provoqué par une boucle infinie, généralement liée à une faute de code. J’étais relativement sceptique sur l’existence d’une telle boucle, puisque je n’avais pas apporté beaucoup de changement de code depuis la dernière compilation complète effectuée un mois en amont.
Recherche de l’origine [1]
J’ai toutefois procédé à une méthode simple, mais généralement efficace pour trouver la source de ce type de bug : commenter la moitié du contenu LaTeX, compiler, voir si le bug se reproduit, si oui commenter la moitié du code restant, sinon inverser et faire un test sur la moitié qu’on n’avait pas testé, et recommencer, et ainsi de suite, jusqu’à cerner la ligne ou le bloc de code qui pose problème. Il s’agit d’une résolution classique par dichotomie, pas nécessairement la plus rapide, mais la plus simple à mettre en œuvre avec LaTeX.
Néanmoins, dans le cas qui m’occupait, une telle recherche s’est révélée infructueuse : le bug ne se produisait que si je compilais l’ensemble de ma thèse, et non pas l’une ou l’autre des moitiés.
Fort heureusement, je savais que j’avais réussi à compiler il y a quelques semaines, et qu’à l’époque j’avais posé un tag git. Grâce à la géniale fonction git bisect, j’ai pu trouver le commit ayant entraîné le bug, en testant par dichotomie l’ensemble de mes commits entre ma dernière compilation réussie et mon tout dernier commit.
Fort heureusement également, ce commit était relativement petit. J’avais remplacé :
\printbibliography[title={Manuscrits},subtype=ms,check=ms_principaux]
par
\begin{refcontext}[sorting=manuscripts]{}
\printbibliography[title={Manuscrits},subtype=ms,check=ms_principaux]
\end{refcontext}
Ceci permet que ma bibliographie consacrée aux manuscrits soit triée selon un ordre spécifique, d’abord par ville, puis par bibliothèque, par collection et par cote.
Recherche de la cause
La modification effectuée est donc la source du problème, mais pourquoi pose-t-elle problème ?
Fonctionnement interne de la bibliographie avec LaTeX + Biber
Un élément a éveillé ma curiosité : le bug se produisait AVANT même que la compilation n’ait eu le temps d’arriver à la ligne sur la bibliographie, comme je pouvais le constater à travers les messages défilant à l’écran.
Cependant, je touchais à un élément concernant la bibliographie. Or, voici comment fonctionne la bibliographie avec LaTeX + biblatex + Biber :
- Lors de la première compilation, LaTeX lit le fichier
.tex
, repère les citations à l’intérieur, et écrit dans un fichier.bcf
les clefs de citations utilisées ainsi que certaines informations relatives au style bibliographique, dont les informations sur le tri de la bibliographie. - Lors de la compilation Biber, ce dernier lit le fichier
.bcf
et le mettant en relation avec le fichier.bib
, il trie et formate la bibliographie sous la forme d’une suite de commande LaTeX, qu’il écrit dans un fichier.bbl
- Lors de la seconde compilation, LaTeX lit non seulement le fichier
.tex
, mais aussi le fichier.bbl
, ce qui lui permet d’ajouter les références bibliographiques et de composer la ou les bibliographies finales.
Ceci est résumé dans le schéma ci-dessous.
Puisque le bug n’arrive qu’à la seconde compilation LaTeX, et qu’il est lié à la bibliographie, le problème se situe probablement dans ma bibliographie. Problème : le commit qui introduit le bug n’a rien changé au fichier .bib. Le problème se situe donc plus vraisemblablement au moment de la production du fichier .bbl
.
Analyse du fichier .bbl
J’ai alors constaté que la taille du fichier .bbl
doublait approximativement entre la compilation avant mon commit et celle après mon commit, passant à 4 Mo dans le second cas. Grâce à un logiciel d’affichage de différence entre fichiers, je constate aisément l’origine de la modification : après mon commit, les entrées bibliographiques sont présentes deux fois dans mon fichier .bbl
: une fois triées selon mon classement par défaut, anonymous+realauthor
, l’autre fois triées selon le classement introduit par mon commit : manuscripts
.
Ceci est du reste parfaitement logique, le tri bibliographique étant effectué par Biber et non par LaTeX, il est normal de trouver pour deux demandes de tri,deux listes bibliographiques dans le fichier .bbl
, chaque liste commençant par \sortlist
et finissant par \endsortlist
. Le problème est qu’avec 1253 entrées bibliographiques, cela produit un fichier très lourd, qui, par conséquent, remplit considérablement la mémoire de LaTeX, et aboutit donc à mon TeX capacity exceeded, sorry [main memory size=5000000]
Résolution du problème
Une fois la cause trouvée, il reste à voir comment se sortir de la situation. Trois solutions s’offrent à nous.
Première solution : utiliser LuaLaTeX
TeX, et XeTeX, les moteurs derrière LaTeX et XeLaTeX fonctionnent selon un modèle à quantité de mémoire disponible fixe : lorsque la compilation est lancée, une certaine quantité de mémoire seulement est utilisable.
En revanche, LuaTeX, derrière LuaLaTeX, fonctionne selon un modèle, plus récent, d’allocation dynamique de la mémoire : la mémoire vive utilisée est étendue au fur et à mesure des besoins, le système d’exploitation veillant simplement à ce que LuaLaTeX n’empiète pas sur les autres programme en activité [2]. Conséquence : la quantité de mémoire utilisable par LuaLaTeX ne dépend que de mon ordinateur, et on peut espérer que ma bibliographie doublée n’en vienne quand même pas à saturer toute la mémoire vive et virtuelle [3] de mon ordinateur.
Problème : LuaTeX est un moteur différent de XeTeX, avec ses spécificités, et, étant dans la phase terminale de ma thèse, je ne préfère pas effectuer une migration avec toutes les vérifications, parfois tenues, que cela implique.
Deuxième solution : augmenter la mémoire de XeLaTeX
Puisque je souhaite continuer à utiliser XeLaTeX, deux solutions s’offrent à moi : résoudre mon problème de double tri ou augmenter la mémoire de XeLaTeX. La seconde solution, moins écologique, est plus rapide à mettre en œuvre et consiste à augmenter la mémoire utilisable par XeLaTeX [4].
Une simple recherche sur le web m’indique la démarche à suivre, pour une installation TeXLive [5] :
- trouver le fichier de configuration de texlive
texmf.cnf
en saisissantkpsewhich texmf.cnf
dans mon terminal ; - dans mon cas, le fichier est
/usr/local/texlive/2016/texmf.cnf
; - ouvrant le fichier je lis les lignes suivantes :
% This texmf.cnf file should contain only your personal changes from the % original texmf.cnf (for example, as chosen in the installer).
Ceci signifie que je peux y mettre tous mes réglages personnels sans risque de perdre les réglages par défaut que je n’aurais pas explicitement modifiés.
- j’ajoute donc le réglage sur de mémoire suivant
main_memory = 7999999
, ayant lu que cela correspond à la quantité maximum gérable par (Xe)TeX. - puis dans mon terminal, saisir
sudo fmtutil-sys --all
pour relancer la création des scriptsXeLaTeX
,LaTeX
et co, à partir de mes nouveaux réglages.
Pour m’assurer que mes réglages aient bien été pris en compte, je lance la compilation avec XeLaTeX d’un fichier minimum :
\documentclass{article}
\begin{document}
\end{document}
J’ouvre le fichier .log
généré, et je lis peu avant la fin :
Here is how much of TeX's memory you used:
196 strings out of 493589
2014 string characters out of 6143511
53785 words of memory out of 7999999
3697 multiletter control sequences out of 15000+600000
3640 words of font info for 14 fonts, out of 8000000 for 9000
1347 hyphenation exceptions out of 8191
23i,1n,17p,127b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
La ligne « 53785 words of memory out of 7999999 » m’indique donc que ma quantité de « words of memory [6] » est passée à 7999999, ce qui correspond à mon nouveau réglage. Ouf !
En relance ma compilation de thèse, tout se passe bien [7].
Troisième solution : éviter d’avoir deux bibliographies triées
Cependant, dans le cas où ma bibliographie grossirait encore sensiblement (ce que je n’espère pas), et pour le principe, il paraîtrait plus utile d’avoir la bibliographie triée une seule fois dans le fichier .bbl
, que ce soit pour les manuscrits ou pour les autres types d’entrées.
De toute façon, je filtre les types d’entrées lors de l’affichage final, pour séparer les manuscrits des autres types.
C’est pourquoi, la version 2.7.0 de biblatex-realauthor, que je viens d’envoyer sur le CTAN propose un nouveau schéma de tri, anonymous+realauthor+manuscripts
, que je peux passer comme option global de biblatex, ce qui me permet de supprimer l’environnement refcontext
que mon commit problématique avait introduit.
En guise de conclusion
- Versionner son travail est très utile. Apprenez à le faire si ce n’est pas déjà fait.
- Si vous avez des problèmes de
TeX capacity exceeded, sorry [main memory size=5000000]
après une compilation biber, et qu’une recherche par dichotomie ne donne rien, regardez la taille du fichier.bbl
.
Vos commentaires
# Le 24 octobre 2016 à 23:13, par Robert Alessi En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Excellent article, très intéressant et utile à d’autres titres que celui-ci. Merci également pour l’ajout de ce nouveau schéma de tri.
Pour ma part, je compile tous mes fichiers à l’aide de LuaLaTeX depuis presque un an. Pour les fichiers les plus complexes, j’ai fait la migration par petits morceaux, en m’assurant à chaque fois que tout passait bien avant d’intégrer le morceau suivant. Le versionnage m’a beaucoup aidé à corriger les erreurs !
# Le 29 janvier 2017 à 11:22, par Paul Gaborit En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Bonne analyse du problème et des différentes solutions. Il est vrai que le premier réflexe avec un telle erreur n’est pas de penser à un problème de bibliographie (d’un autre côté, il est rare de manipuler des documents avec plus de 1000 citations).
Deux remarques de rédaction : (1) j’aurais employé le terme consacré « allocation dynamique de mémoire » plutôt que « attribution dynamique de mémoire » ; (2) dans le graphique décrivant les étapes de compilation, j’inverserais le sens des flèches de lecture (en remplaçant "lit" par "est lu par") pour bien montrer dans quel sens circule l’information.
# Le 29 janvier 2017 à 11:42, par Maïeul En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Effectivement, « allocation » est meilleur qu’« attribution ». J’ai corrigé. Merci.
Par contre, je suis plus réticent à utiliser un passif. J’adore personnellement les passifs, et c’est mon mode de raisonnement le plus courant. Cependant, mon expérience actuelle de reécriture de ma thèse pour correspondre aux logiques les plus courantes montre qu’en général les gens préférent et comprennent mieux l’actif.
De plus, dans le cas présent, je pense que le plus intéressant n’est pas "dans quel sens circule l’information", mais "ce qui se passe à chaque étape de la compilation". Et dans ce cas partir des programmes plutôt que des fichiers est meilleurs. D’où le fait d’avoir mis les 3 blocs de programme au centre, avec une flèche transversale signifiant la chronologie.
# Le 29 janvier 2017 à 15:10, par Paul Gaborit En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Je partage votre avis au sujet de l’usage du passif ou de l’actif. Donc, comme ce sont bien les fichiers « source » qui alimentent les différents outils, je propose l’inversion des flèches et un étiquetage par « alimente » (forme active ;-)).
# Le 29 janvier 2017 à 15:33, par Maïeul En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Ahah ! Bien joué. Je pense cependant qu’il faut rester au niveau du processus de l’utilisateur, qui lance des programmes et ne donne pas directement à manger à ceux-ci.
# Le 5 mars 2018 à 15:19, par Milena Jael Silva En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Bonjour ! Merci beaucoup de ce post. Moi aussi j’ai eu un problème similaire. J’ai rédigé la thèse avec bibtex sur sharelatex mais, au dernier moment, quand je devais rendre la version finale j’ai décidé de changer la bibliographie pour biblatex. Un gros problème car très lent. Ma thèse ne compilait plus. Elle excédait le temps de compilation. J’ai essayé tout. Lualatex xelatex... Etc. Maintenant je préfère revenir en arrière et utiliser bibtex.
# Le 5 mars 2018 à 15:21, par Maïeul En réponse à : Comment ma bibliographie a saturé la mémoire de (Xe)LaTeX
Il ne me seraiz jamais venu à l’idée d’utiliser bibtex....