Les threads utilisent-ils la mémoire virtuelle ou la mémoire réelle?

10

J'essayais d'optimiser mon serveur Linux pour gérer 10 000 threads par processus alors qu'il n'en fait que 382 en ce moment. Conformément à cet article, la formule suivante est utilisée pour connaître le nombre total de threads possibles:

number of threads = total virtual memory / (stack size*1024*1024)

Cela signifie que les threads stockent toutes leurs données dans la mémoire virtuelle. Et au meilleur de ma connaissance, la mémoire virtuelle est un espace d'échange dans une machine Linux qui est stockée sur un disque dur que la RAM ou le cache.

Donc, ma question est de savoir si nos threads utilisent un disque dur pour stocker pour traiter / stocker ses données.

Si oui, cela n'affecte-t-il pas les performances? Pouvons-nous améliorer les performances en les mettant sur la RAM ou le cache? Comment?

Si non, comment fonctionnent exactement les threads?

Mise à jour:

Selon la réponse inutile , la mémoire virtuelle est un système comprenant à peu près:

  • mémoire physique (RAM)
  • tous les fichiers d'échange que vous avez joints
  • prise en charge matérielle pour la traduction des adresses virtuelles en adresses physiques et l'émission d'erreurs de page lorsqu'une adresse virtuelle n'est pas disponible dans la mémoire physique
  • (noyau) prise en charge logicielle pour: gérer les tables de recherche utilisées par ce matériel gérant ces défauts de page en extrayant les pages du swap on demand

Ainsi, tout ce qui se trouve sur la mémoire virtuelle est collectivement sur la RAM (mémoire réelle) et le disque dur (fichiers d'échange). Et comme James l'explique dans sa réponse, la décision sur Ram vs HDD est prise par le noyau en utilisant des algorithmes tels que LRU.

dragosrsupercool
la source
2
à moins que votre serveur ne dispose de 10 000 CPU / cœurs, vous perdez votre temps.
@JarrodRoberson: Pourquoi cela?
dragosrsupercool
3
10000 threads n'est pas un bon moyen de faire évoluer les choses, c'est un bon moyen d'amener un serveur à une analyse, plus de 1 thread par CPU ou Core va juste faire basculer le contexte du serveur et fonctionner plus lentement pas plus vite.
Plus précisément, lorsque vous dites "essayer d'optimiser mon serveur Linux" - qu'essayez-vous d'optimiser? Si c'est le débit, alors un thread par CPU avec multiplexage et E / S non bloquantes sera probablement mieux.
Inutile

Réponses:

12

à ma connaissance, la mémoire virtuelle est un espace d'échange dans une machine Linux

Non, la mémoire virtuelle est un système comprenant à peu près:

  • mémoire physique (RAM)
  • tous les fichiers d'échange que vous avez joints
  • prise en charge matérielle pour la traduction des adresses virtuelles en adresses physiques et l'émission d'erreurs de page lorsqu'une adresse virtuelle n'est pas disponible dans la mémoire physique
  • (noyau) support logiciel pour:
    • gérer les tables de recherche utilisées par ce matériel
    • la gestion de ces défauts de page en extrayant les pages du swap à la demande

Il appartient au noyau de s'assurer que la mémoire virtuelle que vous souhaitez est mise en cache dans la RAM lorsque vous le souhaitez - à moins que vous n'écriviez votre propre couche VM d'espace utilisateur (comme les bases de données le font souvent, iiuc), ne vous inquiétez pas.

Inutile
la source
Ok donc mon hypothèse de mémoire virtuelle était fausse. Quoi qu'il en soit, une question de suivi rapide. Les performances maximales des threads à pleine charge seraient-elles affectées si l'espace SWAP est supérieur à la RAM?
dragosrsupercool
@dragosrsupercool: votre espace de swap sera toujours plus grand que la mémoire physique, sinon il faut utiliser la mémoire virtuelle.
Bryan Oakley
1
@BryanOakley: Ce n'est pas nécessairement vrai. Certains systèmes d'exploitation allouent une page d'échange pour chaque page virtuelle allouée (c'est-à-dire que l'échange doit être au moins aussi grand que physique). D'autres systèmes d'exploitation allouent une page d'échange uniquement lorsqu'il est nécessaire de déplacer une page hors de la mémoire physique (c'est-à-dire que l'échange peut être moins que physique). L'avantage du premier est que si l'allocation réussit, l'échange de cette mémoire est toujours réussi. L'avantage de ce dernier est que vous n'avez pas besoin d'allouer de manière pessimiste d'énormes fichiers d'échange pour tenir compte de situations relativement rares.
mcmcc
1
@dragosrsupercool, les performances ne seront pas affectées par la quantité de RAM, le swap ou le rapport entre eux, sauf si vous êtes faible en RAM et que vous recherchez réellement. sar peut vous parler de l'activité de pagination iirc (cochée: sar -Bsous Linux).
inutile
@Useless: je souhaite augmenter le nombre de threads jusqu'à ce que j'utilise complètement la RAM et que je ne commence pas la pagination.
dragosrsupercool
14

Si le thread est en cours d'exécution, alors l'instruction en cours et toutes les variables que le thread utilise doivent être en mémoire physique.

La plupart des programmes (en fait presque tous) résident dans la mémoire virtuelle et la plupart des programmes utilisent la mémoire virtuelle pour le stockage des variables.

Adresses virtuelles organisées en blocs appelés pages (il s'agit généralement de blocs de 4096 ou 8192 octets).

À tout moment, chaque bloc de mémoire virtuelle est stocké quelque part dans la mémoire réelle ou sur le disque dans «l'espace d'échange» qui lui est réservé.

Votre code de programme traite des adresses virtuelles, lorsque vous vous connectez à une adresse virtuelle ou, si vous demandez l'accès au stockage à une adresse virtuelle, le système (généralement au niveau du matériel) localise l'emplacement actuel de la demande d'adresse et la mappe à votre adresse virtuelle, si l'adresse réside actuellement sur le disque, il la place dans la mémoire réelle, puis mappe l'adresse.

Évidemment, lorsque toute la mémoire physique est utilisée, si quelque chose est paginé, quelque chose d'autre doit être paginé, donc le système recherche la page "Moins récemment utilisée" et la copie sur le disque avant de copier la page que vous avez demandée.

Dans les systèmes modernes, il existe plusieurs optimisations et astuces associées au stockage virtuel.

  • Les adresses sont mappées "par processus". Ainsi, par exemple, tous les programmes C d'une boîte Linux démarrent le processus "principal" à la même adresse.
  • Cela peut permettre à plusieurs processus 32 bits d'occuper et d'utiliser beaucoup plus de 4 Go sur une machine, car une adresse virtuelle 32 bits peut être mappée sur une véritable adresse 64 bits.
  • Lorsque les processus se terminent ou que la mémoire est par ailleurs «libre», le système marque simplement les pages comme libres, elles ne sont jamais recopiées sur le disque d'échange.
  • De même, lorsqu'un nouveau bloc de stockage est demandé, le système saisit simplement une page libre dans la mémoire réelle, non, le disque IO a lieu.
  • Les fonctions de veille et d'hibernation forcent toute la mémoire à être copiée dans l'espace de swap afin que tous les processus en cours et le contenu de la mémoire actuelle puissent être recréés au réveil.
James Anderson
la source
3
Les "tous les programmes C dans une boîte Linux démarrent [principal] à la même adresse" ne semblent pas prendre en compte la randomisation de la disposition de l'espace d'adressage. Cela est de plus en plus utilisé aujourd'hui pour contrecarrer divers schémas d'attaque par écrasement de pile. Bonne réponse sinon, +1.
un CVn
7

Tout d'abord, vous devez en savoir plus sur la mémoire de l'ordinateur , car vous semblez manquer de connaissances dans ce domaine.

Un thread d'exécution est la plus petite unité de traitement pouvant être planifiée par un système d'exploitation. L'implémentation des threads et des processus diffère d'un système d'exploitation à l'autre, mais dans la plupart des cas, un thread est contenu dans un processus. Plusieurs threads peuvent exister dans le même processus et partager des ressources telles que la mémoire, tandis que différents processus ne partagent pas ces ressources.

Ainsi, les threads vont utiliser la mémoire disponible - quel que soit le type disponible. Le nombre de threads que vous pouvez démarrer dépend de la taille de la mémoire et de la quantité de mémoire nécessaire par thread. Si le thread utilise un tas (pas seulement la pile), il a besoin de plus de mémoire et, dans ce cas, vous pouvez démarrer moins de threads.

BЈовић
la source
@VJonvic: +1 pour l'explication de base du thread.
dragosrsupercool
6

La réponse simple à votre question est qu'ils utilisent la mémoire virtuelle. tout utilise la mémoire virtuelle, sauf une poignée de processus liés au système d'exploitation.

D'un autre côté, lorsque votre thread (ou n'importe quel thread, dans n'importe quel processus) est réellement en cours d'exécution, il utilise de la mémoire physique. Les pages de mémoire associées à ce processus sont échangées dans la mémoire physique, où le processeur fait son travail.

Bryan Oakley
la source
3

La mémoire virtuelle est votre RAM plus votre espace de swap. Virtuel signifie simplement que l'adresse que voit votre programme est différente de l'adresse que la puce RAM voit. Si vous devez accéder à la mémoire en swap, le système d'exploitation la déplacera d'abord dans la RAM. Si vous ne voulez aucun échange, désactivez-le. Si vous avez suffisamment de RAM, vous n'en avez pas vraiment besoin.

Cela étant dit, à moins que vous n'ayez un processeur de 10 000 cœurs, l'augmentation à 10 000 threads n'est pas vraiment une «optimisation». Une fois que vous avez suffisamment de threads pour consommer tous les cœurs, plus un ou deux de rechange lorsque ces threads sont bloqués, l'ajout de threads diminue les performances en raison de la surcharge de commutation et des échecs de cache. Vous pouvez toujours vouloir utiliser plus de threads si cela simplifie la logique de votre programme, mais vous compromettez les performances.

Karl Bielefeldt
la source
Oui, 10 000, c'est trop car mon serveur est une machine monocœur 32 bits. En fait, les threads ne sont pas une chose CPU totale. Ce sont des threads de robot, donc ce serait comme attendre parfois la réponse du serveur. Mon objectif est de m'assurer que le processeur est totalement occupé mais pas en surcharge ou en sous-charge. Mais je n'arrive toujours pas à comprendre comment puis-je savoir si le processeur est comme libre ou totalement occupé. Existe-t-il un outil ou une commande?
dragosrsupercool
Je pense que vous pouvez obtenir cette information de la topcommande.
Karl Bielefeldt
@KarlBieledeldt: oui, c'est exactement ce que je cherchais. Une autre question de suivi: je viens juste d'avoir une idée pour explorer que si certains comment un thread peut envoyer une demande d'URL tandis que l'autre thread reçoit la réponse du serveur, je peux garder Utilisation élevée du processeur sans utiliser trop de threads. Est-ce possible? Vous aimez envoyer une demande d'un thread tout en recevant la réponse sur l'autre thread?
dragosrsupercool
2

optimiser mon serveur Linux pour gérer 10 000 threads par processus

Comme d'autres l'ont expliqué, c'est généralement faux. Un thread est une ressource coûteuse , notamment parce qu'il a sa propre pile d'appels (typiquement, un mégaoctet) et parce que c'est une tâche programmable par le noyau. Les threads sont encore plus coûteux que les descripteurs de fichiers ouverts .

Lire Systèmes d'exploitation: trois pièces faciles (manuel téléchargeable gratuitement).

En règle générale, vous ne voulez pas avoir beaucoup de threads, et certainement pas beaucoup de threads exécutables. Le nombre de threads exécutables doit généralement être au plus le nombre de cœurs (ou un petit multiple de cela), donc environ une douzaine au plus. Le nombre de threads dans un processus peut être légèrement supérieur. Donc, à moins d'avoir un serveur très étendu (avec de nombreux sockets et cœurs de processeur), vous ne voulez pas avoir plus d'une douzaine de threads exécutables et une centaine de threads (la plupart étant inactifs) dans votre processus (sur votre bureau) .

Sous Linux, les threads et les processus sont très similaires (car les deux peuvent être créés par clone (2) ) et les deux sont des tâches planifiées par le noyau. En fait, le planificateur du noyau planifie des tâches qui peuvent être des threads à l'intérieur d'un processus multithread, ou le thread principal unique d'un processus à thread unique (dans ce cas, vous nommerez "traiter" ce thread unique), ou les threads du noyau. Vous ne voulez probablement pas avoir plus d'un millier de tâches programmables au total sur votre système de bureau.

Sous Linux, un processus est simplement un groupe de threads partageant le même espace d'adressage virtuel (et partageant d'autres choses, comme une table de descripteurs de fichiers, etc ...). Certains processus n'ont qu'un seul thread.

Un espace d'adressage virtuel est défini par Wikipedia comme

"l'ensemble des plages d'adresses virtuelles qu'un système d'exploitation met à la disposition d'un processus"

(mais voir également cette réponse expliquant que la terminologie n'est pas universelle et que certains documents Microsoft utilisent une définition différente et incompatible ).

Sous Linux, proc (5) est utile pour comprendre l'espace d'adressage virtuel de certains processus. Essayez les deux
cat /proc/self/mapset cat /proc/$$/mapsdans un terminal. Voir aussi ceci , et pmap (1) & ps (1) & top (1) .

Tous les programmes de l'espace utilisateur s'exécutent dans certains processus et utilisent de la mémoire virtuelle afin que chaque processus ait son propre espace d'adressage virtuel. La RAM physique est une ressource gérée par le noyau Linux, et les applications n'ont pas d'accès direct à la RAM (sauf par mmap (2) -ing /dev/mem, voir mem (4) ).

Un processus n'utilise donc pas directement de RAM. Il utilise la mémoire virtuelle et possède son propre espace d'adressage virtuel. Le noyau utilise la pagination pour gérer les pages RAM physiques et fournir l'espace d'adressage virtuel et les abstractions de processus . À tout moment (même lorsque votre processus est inactif ou en cours d'exécution), le noyau peut paginer certaines pages (par exemple les échanger sur le disque). Le noyau configure la MMU (et gère les exceptions matérielles de manque de page dans un gestionnaire d'interruption , soit en récupérant la page à partir du disque, soit en propageant une erreur de segmentation au processus, voir signal (7) )

Vous pouvez avoir des threads verts au-dessus des threads système (mais les bibliothèques de threads verts sont difficiles à implémenter et à déboguer). Regardez dans les goroutines utilisées dans Go pour un exemple de fantaisie. Voir aussi setcontext (3) .

Parfois, votre système peut expérimenter le thrashing . Cela se produit lorsque la mémoire virtuelle totale (nécessaire à tous les processus) dépasse - par un facteur important - la RAM physique disponible. Ensuite, votre ordinateur ne répond plus. En savoir plus sur la taille de l'ensemble résident , la pagination de la demande , l' ensemble de travail , le sur- engagement de mémoire , l' ASLR .

Voir aussi -pour Linux- fork (2) , clone (2) , mmap (2) , madvise (2) , posix_fadvise (2) , mlock (2) , execve (2) , informations d'identification (7) , pthreads (7) , futex (7) , capacités (7) .

Basile Starynkevitch
la source