7
votes

Win32 "Déplacer" la mémoire allouée du tas?

J'ai une application .NET / natif C ++. Actuellement, le code C ++ attribue la mémoire sur le tas par défaut qui persiste pour la vie de l'application. Fondamentalement, les fonctions / commandes sont exécutées dans le C ++ qui entraîne une allocation / modification de la mémoire persistante actuelle. J'échège une approche d'annulation de l'une de ces fonctions / commandes à mi-exécution. Nous avons des centaines de ces commandes et beaucoup sont un code très compliqué (hérité).

L'approche de la force brute que j'essaie d'éviter de modifier chaque commande / fonction pour vérifier l'annulation et effectuer tout le nettoyage approprié (libérant la mémoire de tas). J'échège une approche multi-threadée dans laquelle un fil supplémentaire reçoit la demande d'annulation et termine le thread d'exécution de la commande. Je voudrais que toute la mémoire dynamique soit allouée sur un "tas privé" à l'aide de tasse () (win32). De cette façon, le tas privé pourrait être détruit par le fil manipulant la demande d'annulation. Toutefois, si la commande fonctionne à l'achèvement, j'ai besoin de la mémoire dynamique pour persister. Dans ce cas, j'aimerais faire l'équivalent logique de "déplacer" la mémoire de tas privée au tas par défaut / de processus sans encourir le coût d'une copie réelle. Est-ce de quelque sorte possible? Cela a-t-il même un sens?

Alternativement, je reconnais que je pouvais avoir un nouveau tas privé pour chaque exécution de commandement / fonction (chacun sera un nouveau fil). Le tas privé pourrait être détruit si la commande est annulée ou survivrait si la commande se termine. Y a-t-il un problème avec le numéro des tas poussant indéfiniment? Je sais qu'il y a des frais généraux impliqués dans chaque tas. Quelles limitations pourrais-je rencontrer?

Je suis en cours d'exécution sur Windows 7 64 bits avec 8 Go de RAM (considérez cette plate-forme cible). L'application que je travaille est d'environ 1 million de SLOC (moitié C ++, moitié C #). Je cherche une expérience / des suggestions avec une gestion privée du tas, ou des alternatives à ma solution.


3 commentaires

Demandez-vous si la mémoire que vous allouez dans un tas peut être "réaffectée" à un autre tas sans copier les données?


J'ai 92% sûr que la réponse est non. Mais pas assez pour le poster comme une réponse.


L'allocation de la mémoire en tas n'est pas le seul problème que vous aurez avec les threads de terminaison de force. Le seul moyen sûr de mettre fin à un thread est de l'intérieur. De cette façon, vous savez que le fil n'est pas au milieu d'une opération verrouillée. L'interruptibilité doit être une caractéristique intrinsèque de vos fonctions; Ce n'est pas quelque chose que vous pouvez aller de l'extérieur.


4 Réponses :


1
votes

non. La mémoire ne peut pas être déplacée entre les tas.


0 commentaires

4
votes

Vous serez peut-être mieux avec des processus séparés au lieu de threads séparés:

  • Utilisez des fichiers mappés de mémoire (c.-à-d. Pas un fichier du tout - juste une mémoire partagée transversale)
  • tuer un processus est "plus propre" que de tuer un fil
  • i pense Vous pouvez avoir la mémoire partagée "survivre" le meurtre sans déménagement - vous map / déménagement au lieu de déplacer

    Bien que vous puissiez avoir besoin de faire une certaine gestion de la mémoire.

    Quoi qu'il en soit, la peine d'être examinée. Je cherchais à utiliser la mémoire inter-processus pour quelques autres choses, et il y avait des propriétés inhabituelles (peut rappeler tout cela clairement, il y a quelque temps), et vous pourrez peut-être en profiter.

    juste une idée!


0 commentaires

2
votes

de MSDN Fonctions de tas Page: "La mémoire allouée par le healhaloc n'est pas mobile. L'adresse renvoyée par Healhalloc est valide jusqu'à ce que le bloc de mémoire soit libéré ou réaffecté; le bloc de mémoire n'a pas besoin d'être verrouillé."

Pouvez-vous relier les applications héritées contre votre propre implémentation MALLOC ()? Si tel est le cas, vous devriez être capable de gérer sans modifier le reste du code. Votre bibliothèque MALLOC personnalisée peut suivre les blocs alloués par thread et avoir une fonction "freallylbylthreididididididider () que vous appelez après avoir tué le fil de la fonction héritée. Vous pouvez utiliser des tas privés dans la bibliothèque.

Une alternative à des tas privés peut faire votre propre allocation à partir de fichiers mappés de mémoire. Voir " Création de la mémoire partagée nommée ." Vous créez la mémoire partagée lors de l'initialisation de la bibliothèque Alloc pour le fil hérité. Sur le succès, mappez-le dans le fil principal afin que votre C # puisse y accéder; sur la résiliation, fermez-la et il est libéré au système.


0 commentaires

1
votes

tas est une sorte de gros morceau de mémoire. C'est un gestionnaire de mémoire au niveau de l'utilisateur. Un tas est créé par des appels de mémoire de système de niveau inférieur (par exemple, sbrk sous Linux et virtualalloc sous Windows). Dans un tas, vous pouvez alors demander ou retourner un petit morceau de mémoire par Malloc / Nouveau / Free / Suppr. Par défaut, un processus possède un seul tas (contrairement à la pile, tous les threads partagent un tas). Mais, vous pouvez avoir beaucoup de tas.

  • est-il possible de combiner deux tas avec des tas avec une copie d'un tas? Un tas est essentiellement une structure de données qui conserve une liste de morceaux de mémoire utilisés et libérés. Ainsi, un tas devrait avoir une sorte de données de comptabilité appelées métadonnées. Bien sûr, ces métadonnées sont par tas. Afaik, aucun gestionnaire de tas ne prend en charge une opération de fusion de deux tas. J'avais examiné l'ensemble du code source d'implémentation MALLOC à Linux Glibc ( Mise en œuvre de Doug Lea ), mais aucune opération de ce type. Les fonctions Windows Heap * sont également implémentées de la même manière. Donc, il est actuellement impossible de déplacer ou de fusionner deux tas distincts.

  • est-il possible d'avoir de nombreux tas? Je ne pense pas qu'il devrait y avoir un gros problème pour avoir de nombreux tas. Comme je l'ai déjà dit, un tas est juste une structure de données qui conserve les morceaux de mémoire usagés / libérés. Donc, il devrait y avoir une certaine quantité de frais généraux. Mais, ce n'est pas si sévère. Lorsque vous regardez l'une des MALLOC Mise en œuvre , il y a malloc_state < / code>, qui est une structure de données de base pour chaque tas. Par exemple, vous pouvez créer un autre tas par create_mspace (sous Windows, il est tasse ), alors vous obtiendrez un nouvel état Malloc. Ce n'est pas si grand. Donc, si ce tapis de course (certains surcharges de tas et facilité de mise en œuvre) conviennent, vous pouvez continuer.

    Si j'étais toi, je vais essayer de la façon de décrire. Ça me semble logique. Avoir de nombreux objets de tas ne feraient pas une grande surcharge.

    De plus, il convient de noter que des régions de mémoire techniquement en mouvement sont impossibles. Les pointeurs qui ont pointé la région de la mémoire déplacée entraîneront des pointeurs suspendus.

    P.s. Votre problème semble être une transaction, en particulier la mémoire transactionnelle logicielle. Une implémentation typique de tampons STM en attente de mémoire écrit, puis s'engage à la mémoire du système réel que la transaction n'avait aucun conflit.


1 commentaires

@StingraySc: La cartographie entre l'adresse virtuelle et l'adresse physique n'a rien à voir avec ce problème. Nous ne pouvons tout simplement pas voir une telle cartographie. Nous considérons que le déplacement / la fusion dans l'espace d'adressage virtuel. Les programmeurs ne peuvent voir que l'adresse virtuelle (à l'exception des situations d'émépied ou de mode réel). Oui, la mappage de l'adresse physique peut être toujours modifiée, mais c'est complètement caché. Cependant, le déplacement / la fusion de toit B / W est effectué dans les espaces d'adresses virtuels. Il est donc généralement impossible que si nous mettons en œuvre un mécanisme très coûteux de suivre les pointeurs référencés.