Question

J'ai un problème où un couple 3 dimensions des tableaux allouer une grande quantité de mémoire et le programme a parfois besoin de les remplacer par des plus grands / petits et jette un OutOfMemoryException.

Exemple: il y a 5 alloués matrices de 96Mo (200x200x200, 12 octets de données dans chaque entrée) et le programme a besoin de les remplacer par 210x210x210 (111MB). Il le fait d'une manière similaire à ceci:

array1 = new Vector3[210,210,210];

Où array1-array5 sont les mêmes champs utilisés précédemment. Ceci devrait les anciens tableaux comme candidats pour la collecte des ordures, mais apparemment le GC n'agit pas assez rapidement et laisse les vieux tableaux attribués avant d'allouer les nouvelles - ce qui provoque la OOM - alors que si elles où libérées avant que les nouvelles allocations de l'espace devrait être assez.

Ce que je suis à la recherche est un moyen de faire quelque chose comme ceci:

GC.Collect(array1) // this would set the reference to null and free the memory
array1 = new Vector3[210,210,210];

Je ne sais pas si une collecion complète des déchets serait une bonne idée puisque ce code peut (dans certaines situations) doivent être exécutées assez souvent.

Y at-il une bonne façon de le faire?

Était-ce utile?

La solution

Ce n'est pas une réponse exacte à la question initiale, « comment forcer GC », mais, je pense qu'il vous aidera à réexaminer votre problème.

Après avoir vu votre commentaire,

  • Mettre le GC.Collect (); ne semble aider, altought il ne résout pas le problème complètement - pour une raison quelconque le programme se bloque toujours quand environ 1,3 Go sont alloués (j'utilise System.GC.GetTotalMemory (false), pour trouver le montant réel alloué).

Je suppose que vous pouvez avoir la fragmentation de la mémoire . Si l'objet est grand (85000 octets sous .net 2.0 CLR si je me souviens bien, je ne sais pas si elle a été modifiée ou non), l'objet sera affecté dans un tas spécial, Large Object Heap (LOH) . GC ne récupère la mémoire utilisée par les objets inaccessibles dans LOH, encore, il ne fonctionne pas compactage, dans LOH comme il le fait à d'autres tas (Gen0, gen1 et Gen2), en raison de la performance.

Si vous allouez fréquemment et désallouez gros objets, il fera LOH fragmenté et même si vous avez plus de mémoire libre au total que ce que vous avez besoin, vous ne pouvez pas avoir un espace mémoire contigu plus, par conséquent, va obtenir exception OutOfMemory.

Je ne peux penser à deux solutions de contournement à ce moment.

  1. Déplacer à la machine 64 bits / OS et en profiter :) (facile, mais peut-être le plus dur et en fonction de vos contraintes de ressources)
  2. Si vous ne pouvez pas faire # 1, puis essayez d'allouer un énorme mandrin de mémoire d'abord et de les utiliser (il peut exiger d'écrire une classe d'aide pour manipuler un tableau plus petit, ce qui en fait réside dans un tableau plus large) afin d'éviter la fragmentation . Cela peut aider un peu, mais, il ne peut pas résoudre complètement la question et vous pourriez avoir à faire face à la complexité.

Autres conseils

semble que vous avez rencontré problème de fragmentation LOH (Large tas d'objets).

Large Object Heap

CLR Inside Out Entassé Grand objet Uncovered

Vous pouvez vérifier si vous rencontrez des problèmes de fragmentation de l'aide Loh SOS

Cochez cette question un exemple de la façon d'utiliser SOS pour inspecter le Loh.

Obliger une collection Garbage est pas toujours une bonne idée (il peut réellement favoriser la durée de vie des objets dans certaines situations). Si vous devez, vous pouvez utiliser:

array1 = null;
GC.Collect();
array1 = new Vector3[210,210,210];

est-ce pas cette fragmentation juste grand tas d'objets? Objets> 85.000 octets sont alloués sur le tas d'objets volumineux. Le GC libère de l'espace dans ce tas mais jamais compacter les objets restants. Cela peut entraîner une mémoire contiguë insufficent d'allouer avec succès un grand objet.

Alan.

Si je devais spéculer vous problème est pas vraiment que vous allez de Vector3 [200200200] à un Vector3 [210210210] mais très probablement vous avez des étapes précédentes similaires avant celui-ci:

 i.e.   
    // first you have
    Vector3[10,10,10];
    // then
    Vector3[20,20,20];
    // then maybe
    Vector3[30,30,30];
    //  .. and so on ..
    //  ...
    // then
    Vector3[200,200,200];
    // and eventually you try
    Vector3[210,210,210] // and you get an OutOfMemoryException..

Si cela est vrai, je suggère une meilleure stratégie d'allocation. Essayez sur l'allocation - peut-être doubler la taille chaque fois que, par opposition à allouer toujours juste l'espace que vous avez besoin. Surtout si ces tableaux sont toujours utilisés par des objets qui doivent épingler les tampons (à savoir si cela ont des liens avec le code natif)

Ainsi, au lieu de ce qui précède, quelque chose comme ceci:

 // first start with an arbitrary size
 Vector3[64,64,64];
 // then double that
 Vector3[128,128,128];
 // and then.. so in thee steps you go to where otherwise 
 // it would have taken you 20..
 Vector3[256,256,256];

Ils pourraient ne pas être collectées se parce qu'ils sont référencés quelque part, vous n'êtes pas attendre.

En tant que test, essayez de changer vos références à WeakReferences au lieu et voir si cela résout votre problème OOM. Si elle ne le fait pas alors vous les références ailleurs.

Je comprends ce que vous essayez de faire et de pousser pour la collecte des ordures est immédiate probablement pas la bonne approche (puisque le GC est subtil dans ses manières et rapide à la colère).

Cela dit, si vous voulez cette fonctionnalité, pourquoi ne pas créer?

public static void Collect(ref object o)
{
    o = null;
    GC.Collect();
}

Une exception OutOfMemory déclenche un cycle interne de GC automatiquement une fois et tente à nouveau l'allocation avant de lancer effectivement l'exception à votre code. La seule façon que vous pourriez avoir des exceptions OutOfMemory est si vous tenez des références à trop de mémoire. Effacer les références dès que vous le pouvez en leur attribuant nulle.

Une partie du problème peut être que vous allouer un tableau multidimensionnel, qui est représenté comme un seul bloc contigu de mémoire sur le tas d'objets volumineux (plus de détails ici ). Cela peut bloquer d'autres allocations comme il n'y a pas un bloc contigu à utiliser, même s'il y a encore un peu d'espace libre quelque part, d'où le OOM.

Essayez l'allocation comme un tableau en dents de scie - Vector3 [210] [210] [210] - qui répartit les tableaux autour de la mémoire plutôt que comme un seul bloc, et voir si cela améliore les questions

John, la création d'objets> 85000 octets fera l'objet fin dans le tas d'objets volumineux. Le tas d'objets volumineux est jamais compactée, au lieu de l'espace libre est réutilisé à nouveau. Cela signifie que si vous répartissez des tableaux plus grands à chaque fois, vous pouvez vous retrouver dans des situations où LOH est fragmenté, d'où le OOM.

vous pouvez vérifier cela est le cas en rompant avec le débogueur au point de OOM et d'obtenir une décharge, en soumettant ce décharge à MS par un bug de connexion ( http://connect.microsoft.com ) serait un bon début.

Ce que je peux vous assurer que le GC fera la bonne chose à essayer de vous satisfaire la demande d'allocation, cela inclut le coup d'envoi d'un GC pour nettoyer la vieille poubelle pour satisfaire les nouvelles demandes d'allocation.

Je ne sais pas quelle est la politique de partage de la mémoire sur les décharges Stackoverflow, mais je serais heureux de jeter un oeil à comprendre votre problème plus.

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