#include <vector> typedef std::vector<char> vc; typedef std::vector<vc> vvc; vvc f() { const int N = (1 << 15); return vvc(N, vc(N)); // 1 GB } int main () { vvc v; v = f(); while(true); // Why 2GB allocated ? return 0; } Compiled with both clang -O2 and g++ -O2. Same behavior.Edit: There are multiple ways to fix this code pointed in some of the answers. But my point is to understand this code. Of course there is a temporary object, but it should disappear at the semicolon and 1GB of memory should be returned to the system. The question intends to ask why it does not happen.Edit 2: The destructor of temporary object is indeed called before semicolon.
5 Réponses :
Je viens de tester sur Win32, VC7.
Votre code attribue 2 Go. Si vous changez à ceci: p> Il n'a besoin que de 1 Go. P> Je suppose que la raison - est une opération de copie entre les vecteurs. P> Actions internes de v = f () code> - invoque le constructeur. Votre cas - Par défaut C'TOR et Copy (opérateur
= code>) dans un objet vide. Besoins à l'ivresse 2 Go. P>
F () code> (Création de vecteur et de retour) peut utiliser rvo , et il n'y a pas d'adaptation et d'allocation supplémentaire. P> p>
Je pense que la valeur de retour sera copiée. Que temporaire 2 exemplaires de VVC existe. Chacun avec 2 ^ 30 caractères (= 1 Go) p>
à ma connaissance, le compilateur est autorisé mais non requis pour supprimer l'opération de copie p>
J'ai trouvé ce lien http://en.wikipedia.org/wiki/return_value_optimization P>
Tu as raison, je pense. Mais voyez mon commentaire à Balog Pal répondre.
Vous avez une affectation dans votre code que nous prêchons contre en vain pour une bonne raison; -) P>
Si vous avez utilisé l'initialisation, cela permet une optimisation de la RVO et que d'autres expérimentées semblent également travailler aussi. P>
avec affectation La fonction renvoie un objet, puis il doit être copié à la cible et que ce n'est que Nuke le temporaire. Bien que l'analyse de flux de données, elle pourrait être éventuellement optimisée, c'est un cas difficile à attraper et considéré comme rare d'utiliser. Ainsi, vous subissez la pénalité de performance sur tout le reste. P>
Edit: pour voir que le temporaire est effectivement noué au point approprié, je suggère d'utiliser le débogueur et une étape à une étape. Alternativement regarder la liste des assy. Pour la machine abstrait, l'appel DTor doit se produire avant la prochaine instruction. P>
Cependant, le code optimisé utilise le «comme si» règne plus libéralement. Si le code n'a aucun moyen de dire la différence, cela peut le reporter un peu et vous pouvez simplement ressentir cet effet. P>
C ++ 11 Remarque: En C ++ 11 vecteur a gagné une autre op = qui passe de la rvalue. Cela guérirait ce cas particulier, mais il faudra du temps jusqu'à ce que tous les compilateurs fermeront l'écart et surtout toutes les classes gagnent des trucs en mouvement. Le code pré-11 à la recherche de déménagement utiliserait un échange () à la place de =. P>
En fait, c'est exactement l'un des résous de résolution de sémantique de déménagement de C ++ 11.
Mais pourquoi F () Frame n'est-elle pas libérée? Il devrait arriver de toute façon, même avant alors que (vrai); code>. Je ne peux pas voir la demande d'optimisation ici. La mémoire dynamique de base sémantique devrait fonctionner.
@Capellic, il a probablement été publié, le système d'exploitation ne l'a tout simplement pas encore récupéré.
@Capellic, de nombreux allocateurs ne relâchent jamais la mémoire au système d'exploitation, en particulier pour les petits morceaux. Il peut être récupéré dans le processus - la récréation du vecteur ne provoquera pas une augmentation de 3 Go.
@KonRADRUDOLPH: Oui, je pense que cela pourrait être le centre de la question. Sinon, devrait être un gros bug dans ces compilateurs.
@Capellic: Ce qui vous manque, c'est que l'objet renvoyé de la fonction habite dans le cadre de la pile de l'appelant. Le cadre de pile f () code> est libéré, mais la valeur renvoyée de
f () code> vit dans
principale code>. En tout état de cause, en ignorant que, estimant que les deux vecteurs doivent être vivants en même temps pour que la copie des valeurs réussisse. À ce stade, votre programme consomme 2G de mémoire et l'allocator ne relâchera probablement pas cette mémoire au système d'exploitation. Si vous souhaitez essayer cela, créez votre propre allocator (allocator C ++) et transmettez-le au vecteur, puis de mesurer la mémoire
@ Davidrodríguez-Dribesas: Pourquoi pensez-vous que cela me manque? La valeur en main est une taille de 1 Go (quelque chose de plus), et c'est le point de la question.
Le point de ce code n'est pas comment le réparer mais la comprendre.
@Capellic: "GRATUIT" de la vue du programme et "GRATUITEMENT" de la vue du système d'exploitation n'est pas la même. En effet, dans la plupart des systèmes d'exploitation, le programme ne peut pas i> donner à 1 Go à l'OS dans cette situation.
@Capellic: Non C'est ce que je pense manquant: la taille maximale requise dans principal code> est de 2 Go non 1 Go. Dans le contexte de
principal code> la valeur renvoyée de
f () code> et
v code> sont vivants et avec la même taille 1 Go en même temps. Pour une brève période, mais la quantité consommée dans b>
principale code> à un point est de 2 Go. Semblable à
int main () {big1gtype obj1; {big1gtype obj2; }} code>
Bien que temporairement principal a besoin de 2 Go de 2 Go, en (vrai), il devrait avoir déjà besoin de 1 Go, mais en fait en fait 2 Go.
Avez-vous cherché des choses après 'éditer:'?
Je suppose que vous envisagez l'affichage du système d'exploitation de la quantité de mémoire allouée à le processus em> et que votre compilateur ne prend pas encore en charge l'affectation de déplacement de C ++ 11. < / p>
Par conséquent, ce qui se passe est probablement ce qui suit: p>
Donc, le résultat est que le système d'exploitation alloue 2 Go à votre processus, dont 1 Go est attribué au vecteur et 1 Go est libre pour une allocation future dans votre programme (mais pas aux allocations d'un autre processus). P>
EDIT: Il existe plusieurs façons de corriger ce code pointé dans une partie de la réponses. Mais mon point est de comprendre ce code. Bien sûr il y a un objet temporaire, mais il devrait disparaître au point-virgule et 1 Go de La mémoire doit être retournée sur le système. La question a l'intention de demander pourquoi cela ne se produit pas. P> blockQuote>
sur Windows j'ai compilé votre test avec GCC et Ran. Et je vois que la valeur de
d'octets privés code> augmente après le début du programme, puis commence à diminuer puis cesser de changer. Donc, sur cette mémoire du système d'exploitation est renvoyée au système. À la manière dont j'ai utilisé
Process Explorer Code> pour obtenir des informations sur
d'octets privés code>. P>
Je suppose que vous avez fait votre test sur Linux et sur cette mémoire du système d'exploitation n'est pas retourné au système. S'il n'est pas utilisé, il est finalement déplacé dans une zone de pagination si j'ai raison. P>
C'est la chose d'affectation. Avec
std = c ++ 11 code> c'est 1 Go.
Avez-vous essayé de récupérer la mémoire en excès, par exemple en lancant un autre exemple de ceci. Qu'advient-il de la première instance?
4ème processus a écrasé ma machine (8 Go de RAM).
Comment mesurez-vous la mémoire utilisée? Si vous retournez 1 Go à l'allocator, cela ne signifie pas que l'allocator renverra nécessairement 1 Go au système d'exploitation.