Laden...

RAM mitzählen

Erstellt von cmpxchg vor 18 Jahren Letzter Beitrag vor 18 Jahren 2.787 Views
C
cmpxchg Themenstarter:in
192 Beiträge seit 2005
vor 18 Jahren
RAM mitzählen

Hallo,
gibt es eine möglichkeit den Speicherverbrauch von objekten zu bestimmen?

Im konkreten fall hab ich eine ArrayList, die gefüllt ist mit Strukturen.
Ich will also den Speicher, den die ArrayList für die Verwaltung braucht und die Summe des Speichers, die jede Struktur belegt.

Danke im Voraus für die Hilfe

564 Beiträge seit 2006
vor 18 Jahren

hi!

Du kannst es binär serialisieren und so die Größe bestimmen. Die Daten, welche beim serialisieren herauskommen sind ein wenig größer, aber wenn du nicht byte-genau rechnen möchtest, wäre das eine Möglichkeit.

der Marcel

:] 😄Der größte Fehler eines modernen Computers sitzt meist davor 😁 :]

B
342 Beiträge seit 2006
vor 18 Jahren

Hi,
das geht doch mit sizeof(object) viel einfacher, allerdings musst du den Code dann als unsafe markieren.
Big Al

Da man Spatzen nicht mit Kanonen jagt, sollte man auch nicht mit Computern auf Spatzenhirne losgehen.

6.862 Beiträge seit 2003
vor 18 Jahren

Bei den integralen Datentypen muss man nicht mehr nen unsafe Block verwenden wenn man sizeof benutzt, des ist neu mit 2.0. Bei Strukturen brauch man das aber noch.

Was aber gleich geblieben ist, sizeof akzeptiert nur ValueTypes, also wirst du damit nicht weit kommen bei der Arraylist.

Baka wa shinanakya naoranai.

Mein XING Profil.

4.221 Beiträge seit 2005
vor 18 Jahren

Original von Big Al
allerdings musst du den Code dann als unsafe markieren.

Bei der Verwendung von Marshal.SizeOf muss nichts als unsafe markiert werden (auch in 1.1 nicht)

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

S
8.746 Beiträge seit 2005
vor 18 Jahren

Frage: Wozu brauchst du die Information über die Speichergröße?

C
cmpxchg Themenstarter:in
192 Beiträge seit 2005
vor 18 Jahren

Ich brauche es zur Fehlersuche: Mein Serverprogramm verbraucht 1,2GB RAM.
Doch warum?
Bevor ich da vermutungen anstelle, will ich erstmal testen, ob dieser wert realistisch ist, weil er wirklich belegt wird, oder ob nur der GC den Speicher nicht freigibt.
Ausserdem will ich damit feststellen, welche Teile wie viel Speicher belegen und somit die Speicherauslastung optimieren.

6.862 Beiträge seit 2003
vor 18 Jahren

Dafür gibts doch Programme wie z.b. Compuware DevPartern die nen Memory Profiler besitzen. Wobei die sich des auch gut bezahlen lassen 🙂 Denke es gibt auch sicherlich gute weniger kostspielige Produkte.

Baka wa shinanakya naoranai.

Mein XING Profil.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Daher auch meine Frage:

Benutze - wie vorgeschlagen - einen Memory-Profiler. Der sagt dir nicht nur, wieviel Speicher von welchem Typ belegt wird, sondern auch WANN. Das ist bei einem GC-System viel wichtiger. MS selbst liefert einen kostenlosen Profiler mit.

Wahrscheinlichste Ursache für dein Speicherproblem dürften sein:

* fehlendes Dispose() (kannst du ganz gut rausfinden ob das dein Problem ist, wenn du mal den GC in allen Generationen ausführst und dann guckst, wieviel managed Speicher noch belegt ist, wenn du 2 MB belegst aber der Taskmanager behauptet es sein 100, dann hast du 98 MB unmanaged Speicher nicht freigegeben, abzüglich Runtime).
* Allokieren großer Blöcke (kommen in Gen 2)

C
cmpxchg Themenstarter:in
192 Beiträge seit 2005
vor 18 Jahren

Wo finde ich den Memory Profiler für .NET?

N
750 Beiträge seit 2004
vor 18 Jahren

Original von cmpxchg
Wo finde ich den Memory Profiler für .NET?

google?
Google Such Link

?( wer suchet, der findet auch! :]

C
cmpxchg Themenstarter:in
192 Beiträge seit 2005
vor 18 Jahren

Ich suche doch den kostenlosen von Microsoft.

F
10.010 Beiträge seit 2004
vor 18 Jahren

Dann such doch bei msdn.microsoft.com
Wo sollte das wohl sonst zu finden sein.

308 Beiträge seit 2005
vor 18 Jahren

Hi,

ich habe mal eine funktion geschrieben, die den tatsächlichen Speicherverbrauch eines Objeltes inklusive alle properties berechnen sollte.

Die is nicht perfekt, aber man kann mit den ergebnissen was anfangen.
(zumindest ich konnte damit Design-Schwächen in einer monster klasse finden (die hatte eine menge von Listen als Properties die dann auch wieder listen oder komplexe objekte beinhalten konnten).

hier der Code:

using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Runtime.InteropServices;

namespace MemoryTest
{

	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	class MemHelper
	{


		public static long GetMemoryConsumption(object o)
		{
			return MemHelper.GetMemoryConsumption(o,null,"Object");
		}

		public static long GetMemoryConsumption(object o, ArrayList countedObjects, string parentName)
		{
			long result = 0;
			if (o != null)
			{
				// System.Console.Out.WriteLine("Checking: "+o.GetType().FullName);
				if (o is String)
				{
					result += ((string)o).Length;
				}
				else
				{
					Type valType =  o.GetType();
					if (valType.IsValueType)
					{
						if (valType.IsEnum)
						{
							
							result += System.Runtime.InteropServices.Marshal.SizeOf(Enum.GetUnderlyingType(valType));
						}
						else
						{
							// Date timeß
							if (o is System.DateTime) 
							{
								// spezial treatment
								result += 8;
							}
							else
							{
								result += System.Runtime.InteropServices.Marshal.SizeOf(o);
							}
						}
					}
					else
					{
						if (o is System.Reflection.Pointer)
							return 16;

						if (countedObjects == null)
							countedObjects = new ArrayList();

						// avoid double counting of referenced objects....
						if (countedObjects.Contains(o))
							return 0;

						

						// size of the instance itself...
						// ... result +=  ??? 

						countedObjects.Add(o);
						FieldInfo[] objectFields=  valType.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic  /*| BindingFlags.Static*/);
						foreach(FieldInfo fi in objectFields)
						{
							string currentName = parentName+"."+fi.Name;
							object val = fi.GetValue(o);
							// is an list or array??
							if (valType.IsArray)
							{
								Array ar = (Array)val;
								foreach(object oArr in ar)
									result+=GetMemoryConsumption(oArr,countedObjects,currentName);
							}
								/* else if (val is MemoryStream)
								{
									if (((MemoryStream)val).Is
									result += ((MemoryStream)val).Capacity;
								} */
							else if (val is System.Array)
							{
								System.Array arr = (System.Array)val;
								if (arr.Length > 0)
								{
									Type checkTypeObject = null;
									bool valueTypeArray = true;
									for(int i=0; i < arr.Length;i++)
									{
										object arrVal = arr.GetValue(i) ;
										if (arrVal != null)
										{
											if  (checkTypeObject == null) 
											{
												
												checkTypeObject = arrVal.GetType();
												if (!checkTypeObject.IsValueType)
												{
													valueTypeArray = false;
												}
												break;
											}
										}

									}

									
									if  ( (checkTypeObject != null) &&  (valueTypeArray) )
									{
										// simply use count*sizeof type... 
										result+=arr.Length*System.Runtime.InteropServices.Marshal.SizeOf(checkTypeObject);
									}
									else
									{
										// count each element 
										foreach(object oArr in arr)
											result+=GetMemoryConsumption(oArr,countedObjects,currentName);
									} 
								}
								
							}
							else if (val is IList)
							{
								IList list = (IList)val;
								lock(list.SyncRoot)
								{
									for(int i=0;i< list.Count;i++)
									{
										object oList =list[i];
										result+=GetMemoryConsumption(oList,countedObjects,String.Format("{0}[{1}]",currentName,i));
										i++;
									}
								}
							}
							else if (val is IDictionary)
							{
								IDictionary dict = (IDictionary)val;
								lock(dict.Keys.SyncRoot)
								{
									foreach(object key in dict.Keys)
									{
										result+=GetMemoryConsumption(key,countedObjects,currentName);
										object item = dict[key];
										result+=GetMemoryConsumption(item,countedObjects,String.Format("{0}[{1}]",currentName,key.ToString()));
									}
								}
							}
							else
							{
								result += GetMemoryConsumption(val,countedObjects,currentName);


							}
						}
					}
				}
			}

			return result;
		}
	}
}

Das Ergebnis von MemTest.GetMemoryConsumption(o) ist nicht 100% korrekt aber schon ziemlich genau. Um einen überblick zu bekommen, was so ein objekt an speicher bindet ist es recht interesant.

Ein schöne Erweiterung zum debuggen ist es auch zu schauen, welche objekte IDisposable implementieren und dann im Code prüfen, ob man die auch alle objekte Disposed/Closed etc...