Question

Rubis est vraiment gourmand en mémoire - mais vaut également chaque instant.

Que faites-vous pour maintenir une faible utilisation de la mémoire ?Évitez-vous les grosses chaînes et utilisez-vous plutôt des tableaux/hachages plus petits ou n'y a-t-il aucun problème à vous soucier et laissez-vous le ramasse-miettes faire le travail ?

Modifier:J'ai trouvé un bel article sur ce sujet ici - vieux mais toujours intéressant.

Était-ce utile?

La solution

  1. Choisissez des structures de date qui sont des représentations efficaces, évoluez bien et faites ce dont vous avez besoin.
  2. Utilisez des algorithmes utilisant des structures de données efficaces plutôt que gonflées, mais plus faciles.
  3. Regardez ailleurs où. Ruby a un pont en C et il est beaucoup plus facile d’être conscient de la mémoire en C qu’en Ruby.

Autres conseils

J'ai découvert que Rubusion Enterprise Edition de Phusion (une fourche de Ruby principale avec un système de récupération des ordures bien amélioré) pouvait considérablement améliorer l'utilisation de la mémoire ... De plus, ils l'ont rendue extrêmement facile à installer (et à supprimer , si vous en trouvez le besoin).

Vous pouvez en savoir plus et le télécharger sur leur site Web .

Je ne pense vraiment pas que cela compte autant. Rendre votre code moins lisible afin d’améliorer la consommation de mémoire est une chose que vous ne devriez jamais faire que si vous en avez besoin . Et par besoin, je veux dire un cas spécifique pour le profil de performances et des indicateurs spécifiques qui indiquent que tout changement résoudra le problème.

Si vous utilisez une application dans laquelle la mémoire sera le facteur limitant, Ruby n’est peut-être pas le meilleur choix. Cela dit, j'ai constaté que mes applications Rails utilisent généralement environ 40 à 60 Mo de RAM par instance Mongrel. Dans l’ordre des choses, ce n’est pas beaucoup.

Vous pourrez peut-être exécuter votre application sur la machine virtuelle Java avec JRuby - la machine virtuelle Ruby n’est pas aussi avancée que la machine virtuelle pour la gestion de la mémoire et le garbage collection. La version 1.9 apporte de nombreuses améliorations et d'autres machines virtuelles sont en cours de développement.

Les développeurs Ruby ont beaucoup de chance puisqu’ils n’ont pas à gérer eux-mêmes la mémoire.

Sachez que Ruby alloue des objets, par exemple quelque chose d'aussi simple que

100.times{ 'foo' }

alloue 100 objets chaîne (les chaînes sont mutables et chaque version nécessite sa propre allocation de mémoire).

Assurez-vous que si vous utilisez une bibliothèque allouant beaucoup d'objets, que d'autres alternatives ne sont pas disponibles et que votre choix vaut la peine de payer le coût du ramasse-miettes.(vous n'aurez peut-être pas beaucoup de requêtes ou ne vous soucierez peut-être pas de quelques dizaines de ms par requête).

La création d'un objet de hachage alloue en réalité plus qu'un objet, par exemple

{'joe' => 'male', 'jane' => 'female'}

n'attribue pas 1 objet mais 7.(un hachage, 4 chaînes + 2 chaînes clés)

Si vous pouvez utiliser des clés de symboles, car elles ne seront pas récupérées.Cependant, comme elles ne seront pas récupérées, vous devez vous assurer de ne pas utiliser de clés totalement dynamiques, comme la conversion du nom d'utilisateur en symbole, sinon vous « perdrez » de la mémoire.

Exemple: Quelque part dans votre application, vous appliquez un to_sym sur le nom d'un utilisateur comme :

hash[current_user.name.to_sym] = something

Quand vous avez des centaines d’utilisateurs, ça peut aller, mais que se passe-t-il si vous avez un million d’utilisateurs ?Voici les chiffres :

ruby-1.9.2-head >
# Current memory usage : 6608K
# Now, add one million randomly generated short symbols
ruby-1.9.2-head > 1000000.times { (Time.now.to_f.to_s).to_sym }

# Current memory usage : 153M, even after a Garbage collector run.

# Now, imagine if symbols are just 20x longer than that ?
ruby-1.9.2-head > 1000000.times { (Time.now.to_f.to_s * 20).to_sym }
# Current memory usage : 501M

Soyez conscient de ne jamais convertir d'arguments non contrôlés en symbole ou de vérifier des arguments auparavant, cela peut facilement conduire à un déni de service.

Pensez également à éviter les boucles imbriquées de plus de trois niveaux de profondeur car cela rend la maintenance difficile.Limiter l'imbrication des boucles et des fonctions à trois niveaux ou moins est une bonne règle de base pour maintenir le code performant.

Voici quelques liens à ce sujet :

http://merbist.com

http://blog.monitis.com

  1. Lorsque vous déployez une application Web Rails / Rack, utilisez REE ou un autre interpréteur facilitant la copie sur écriture.
  2. Ajustez le ramasse-miettes (voir https://www.engineyard.com/blog/tuning-the-garbage-collector-with-ruby-1-9-2 , par exemple)
  3. Essayez de réduire le nombre de bibliothèques / gemmes externes que vous utilisez car un code supplémentaire utilise la mémoire.
  4. Si une partie de votre application nécessite beaucoup de mémoire, vous pouvez peut-être la réécrire dans une extension C ou la compléter en appelant d'autres programmes / plus rapides / mieux optimisés (si vous devez traiter de grandes quantités de données texte , vous pouvez peut-être remplacer ce code par des appels à grep, awk, sed, etc.)

Je ne suis pas un développeur Ruby, mais je pense que certaines techniques et méthodes sont valables pour toutes les langues:

Utilisez la variable de taille minimale appropriée au travail

Détruit et ferme les variables et les connexions lorsqu'il n'est pas utilisé
Toutefois, si vous avez un objet que vous devrez utiliser plusieurs fois, pensez à le garder dans son champ d'application. Toutes les boucles comportant des manipulations d'une grande chaîne dp le travail sur une chaîne plus petite, puis l'ajoute à une chaîne plus grande.

Utilisez une gestion des erreurs décente (essayez finalement de rattraper) pour vous assurer que les objets et les connexions sont fermés

Lorsque vous utilisez des ensembles de données, ne renvoyez que le minimum nécessaire

Sauf dans les cas extrêmes, l'utilisation de la mémoire n'est pas un sujet de préoccupation. Le temps que vous passez à essayer de réduire l’utilisation de la mémoire vous rapportera LOT de giga-octets.

Consultez le logiciel de petite mémoire - Patterns pour les systèmes à mémoire limitée . Vous ne spécifiez pas quel type de contrainte de mémoire, mais je suppose que RAM. Bien que non spécifiques à Ruby, je pense que vous trouverez quelques idées utiles dans ce livre - les modèles couvrent la RAM, la ROM et le stockage secondaire, et sont divisés en techniques principales de petites structures de données, allocation de mémoire, compression, stockage secondaire et petits. architecture.

La seule chose que nous ayons jamais eu à nous préoccuper est RMagick.

La solution consiste à utiliser la version 2 de RMagick et à appeler Image#destroy! quand vous avez fini d'utiliser votre image

Évitez le code comme celui-ci:

str = ''
veryLargeArray.each do |foo|
  str += foo
  # but str << foo is fine (read update below)
end

qui créera chaque valeur de chaîne intermédiaire sous forme d'objet String, puis supprimera sa seule référence à la prochaine itération. Cela engouffre la mémoire avec des tonnes de chaînes de plus en plus longues qui doivent être récupérées.

À la place, utilisez Array#join:

str = veryLargeArray.join('')

Ceci est implémenté en C très efficacement et n'entraîne pas la surcharge de création de String.

UPDATE: Jonas a raison dans le commentaire ci-dessous. Mon avertissement est valable pour += mais pas <<.

Je suis assez nouveau chez Ruby, mais je n’ai pas encore jugé nécessaire de faire quelque chose de spécial à cet égard (c’est-à-dire plus que ce que j’ai tendance à faire en tant que programmeur en général). C’est peut-être parce que la mémoire coûte moins cher que le temps qu’elle faudrait pour l’optimiser sérieusement (mon code Ruby s’exécute sur des machines disposant de 4 à 12 Go de RAM). Cela peut également être dû au fait que les travaux pour lesquels je l’utilise ne durent pas longtemps (c’est-à-dire que cela dépendra de votre application).

J'utilise Python, mais je suppose que les stratégies sont similaires.

J'essaie d'utiliser de petites fonctions / méthodes afin que les variables locales soient automatiquement récupérées lorsque vous revenez à l'appelant.

Dans les fonctions / méthodes plus importantes, je supprime explicitement les objets temporaires volumineux (tels que les listes) lorsqu'ils ne sont plus nécessaires. Fermer les ressources le plus tôt possible peut aussi aider.

Il convient de garder à l’esprit le cycle de vie de vos objets. Si vos objets ne sont pas trop transmis, le ramasse-miettes finira par entrer en jeu et les libérer. Cependant, si vous continuez à les référencer, le ramasse-miettes peut avoir besoin de plusieurs cycles pour les libérer. Ceci est particulièrement vrai dans Ruby 1.8, où le ramasse-miettes utilise une mauvaise mise en œuvre de la technique de marquage et balayage.

Vous pouvez rencontrer cette situation lorsque vous essayez d'appliquer certains & "modèles de conception" & ";" comme un décorateur qui garde longtemps des objets en mémoire. Cela n’apparaît peut-être pas évident lorsque vous essayez d’exemple seul, mais dans les applications du monde réel où des milliers d’objets sont créés en même temps, le coût de la croissance de la mémoire sera considérable.

Dans la mesure du possible, utilisez des tableaux au lieu d'autres structures de données. Essayez de ne pas utiliser de float quand un entier fera l'affaire.

Faites attention lorsque vous utilisez les méthodes gem / library. Ils peuvent ne pas être optimisés en mémoire. Par exemple, la classe Ruby PG :: Result a une méthode 'valeurs' qui n'est pas optimisée. Il utilisera beaucoup de mémoire supplémentaire. Je n'ai pas encore signalé cette erreur.

Le remplacement de la mise en œuvre de malloc (3) par jemalloc réduira immédiatement votre consommation de mémoire de 30%. J'ai créé le joyau 'jemalloc' pour y parvenir instantanément.

J'essaie de garder les tableaux & listes & amp; ensembles de données aussi petits que possible. Les objets individuels importent peu, car la création et le ramassage des ordures sont assez rapides dans la plupart des langues modernes.

Dans les cas où vous devez lire une sorte d’énorme ensemble de données dans la base de données, assurez-vous de le lire de manière avant / arrière et de le traiter par petits morceaux au lieu de tout charger en mémoire en premier.

n'utilisez pas beaucoup de symboles, ils restent en mémoire jusqu'à ce que le processus soit tué .. ceci car les symboles ne sont jamais ramassés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top