J'ai une application qui est utilisée dans le traitement de l'image, et je me retrouve généralement l'allocation des tableaux dans le 4000x4000 ushort taille, ainsi que les occasionnels flotteur et le comme. Actuellement, l' .NET framework a tendance à se bloquer dans cette application, apparemment au hasard, presque toujours avec une erreur de mémoire insuffisante. 32 mo n'est pas une énorme déclaration, mais si .NET est la fragmentation de la mémoire, alors il est très possible que ces grandes continu allocations de ne pas se comporter comme prévu.
Est-il un moyen de dire à la poubelle collecteur à être plus agressifs, ou à la défragmentation de la mémoire (si c'est ça le problème)? Je me rends compte qu'il y a de la GC.Recueillir et GC.WaitForPendingFinalizers appels, et j'ai saupoudré assez généreusement par le biais de mon code, mais je suis quand même à faire des erreurs. Il est peut-être parce que je suis d'appeler les routines dll que l'utilisation de code natif beaucoup, mais je ne suis pas sûr. J'ai dépassé que du code C++, et assurez-vous que la mémoire je déclare que je supprime, mais encore obtenir ces C# se bloque, donc je suis sûr que ce n'est pas là. Je me demande si le C++ appels pourraient interférer avec la GC, le rendant laisser derrière mémoire, car une fois interagi avec un appel des indigènes, est-ce possible? Si oui, puis-je activer cette fonctionnalité off?
EDIT: Voici des code qui sera la cause de la panne. Selon ce DONC, la question, je n'ai pas besoin d'être mise au rebut de la BitmapSource objets ici. Voici la version naïve, pas de GC.Recueille en elle. Généralement, il se bloque à l'itération 4 à 10 de l'annulation de la procédure. Ce code remplace le constructeur dans un vide projet WPF, depuis que je suis en utilisant WPF. Je ne les délires avec les bitmapsource en raison des limitations je l'ai expliqué dans ma réponse à @dthorpe ci-dessous ainsi que les conditions énumérées dans cette SORTE de question.
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
//Attempts to create an OOM crash
//to do so, mimic minute croppings of an 'image' (ushort array), and then undoing the crops
int theRows = 4000, currRows;
int theColumns = 4000, currCols;
int theMaxChange = 30;
int i;
List<ushort[]> theList = new List<ushort[]>();//the list of images in the undo/redo stack
byte[] displayBuffer = null;//the buffer used as a bitmap source
BitmapSource theSource = null;
for (i = 0; i < theMaxChange; i++) {
currRows = theRows - i;
currCols = theColumns - i;
theList.Add(new ushort[(theRows - i) * (theColumns - i)]);
displayBuffer = new byte[theList[i].Length];
theSource = BitmapSource.Create(currCols, currRows,
96, 96, PixelFormats.Gray8, null, displayBuffer,
(currCols * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
System.Console.WriteLine("Got to change " + i.ToString());
System.Threading.Thread.Sleep(100);
}
//should get here. If not, then theMaxChange is too large.
//Now, go back up the undo stack.
for (i = theMaxChange - 1; i >= 0; i--) {
displayBuffer = new byte[theList[i].Length];
theSource = BitmapSource.Create((theColumns - i), (theRows - i),
96, 96, PixelFormats.Gray8, null, displayBuffer,
((theColumns - i) * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
System.Console.WriteLine("Got to undo change " + i.ToString());
System.Threading.Thread.Sleep(100);
}
}
}
Maintenant, si je suis explicite dans l'appel de l'garbage collector, j'ai pour envelopper l'ensemble du code dans une boucle externe à cause de la OOM crash. Pour moi, cela a tendance à se produire autour de x = 50:
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
//Attempts to create an OOM crash
//to do so, mimic minute croppings of an 'image' (ushort array), and then undoing the crops
for (int x = 0; x < 1000; x++){
int theRows = 4000, currRows;
int theColumns = 4000, currCols;
int theMaxChange = 30;
int i;
List<ushort[]> theList = new List<ushort[]>();//the list of images in the undo/redo stack
byte[] displayBuffer = null;//the buffer used as a bitmap source
BitmapSource theSource = null;
for (i = 0; i < theMaxChange; i++) {
currRows = theRows - i;
currCols = theColumns - i;
theList.Add(new ushort[(theRows - i) * (theColumns - i)]);
displayBuffer = new byte[theList[i].Length];
theSource = BitmapSource.Create(currCols, currRows,
96, 96, PixelFormats.Gray8, null, displayBuffer,
(currCols * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
}
//should get here. If not, then theMaxChange is too large.
//Now, go back up the undo stack.
for (i = theMaxChange - 1; i >= 0; i--) {
displayBuffer = new byte[theList[i].Length];
theSource = BitmapSource.Create((theColumns - i), (theRows - i),
96, 96, PixelFormats.Gray8, null, displayBuffer,
((theColumns - i) * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
GC.WaitForPendingFinalizers();//force gc to collect, because we're in scenario 2, lots of large random changes
GC.Collect();
}
System.Console.WriteLine("Got to changelist " + x.ToString());
System.Threading.Thread.Sleep(100);
}
}
}
Si je suis une mauvaise manipulation de la mémoire dans les deux cas, si il y a quelque chose que je devrais place avec un profiler, laissez-moi savoir. C'est assez simple routine là.
Malheureusement, il ressemble à @Kevin réponse est juste, c'est un bug .NET et comment .NET pour gérer les objets de plus de 85k. Cette situation me paraît extrêmement étrange, pourrait Powerpoint être réécrit .NET avec ce genre de limitation, ou l'un des autres applications de bureautique? 85k ne me semble pas être un ensemble beaucoup d'espace, et j'avais aussi penser que tout programme qui utilise des soi-disant "grands" allocations fréquemment deviendrait instable dans une affaire de quelques jours à quelques semaines lors de l'utilisation .NET.
EDIT: Il semble que Kevin est droit, c'est une limitation de .NET GC. Pour ceux qui ne veulent pas suivre la totalité du fil, des .NET a quatre GC tas: gen0, gen1, gen2, et LOH (Objets Volumineux). Tout ce qui est 85k ou plus petit va sur l'un des trois premiers segments de mémoire, en fonction de l'heure de création (déplacé de gen0 à gen1 à gen2, etc). Des objets de plus de 85k placés sur la liturgie des heures. La liturgie des heures est jamais compacté, afin, éventuellement, de la répartition du type, je suis en train de faire finira par causer une OOM erreur comme des objets dispersés que l'espace mémoire. Nous avons trouvé que le passage à la .NET 4.0 ne aider un peu le problème, le fait de retarder l'exception, mais pas l'empêcher. Pour être honnête, cela se sent un peu comme le 640k barrière-- 85k devrait être suffisant pour n'importe quel utilisateur de l'application (pour paraphraser cette vidéo d'une discussion de la GC dans le .NET). Pour l'enregistrement, Java ne présentent pas ce comportement avec ses GC.