Stack vs Heap

Signaler
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
-
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
-
Pour ceux que ca intéresse je viens de faire un test.. Il parait qu'avec .NET l'allocation dynamique sur le tas est quasiment aussi rapide que l'allocation sur la pile.. Pas si sûr..

namespace Test
{
class App
{
[ System.Runtime.InteropServices.DllImport( "kernel32.dll" ) ]
[ System.Security.SuppressUnmanagedCodeSecurity ]
private static extern int QueryPerformanceCounter( ref long count );


private static long ticks = 0;


private static long Ticks
{
get
{
QueryPerformanceCounter( ref ticks );
return ticks;
}
}


private unsafe static void Stack( )
{
byte* p = stackalloc byte[ 256 ]; // Attention à StackOverflowException.
}


private static void Heap( )
{
byte[ ] tab = new byte[ 256 ];
}


private static void Main( )
{
long ticks = 0;
long stack = 0;
long heap = 0;


Stack( ); // JIT
Heap( ); // JIT


ticks = Ticks;
for ( int i = 0; i < 1000; i++ )
Stack( );
stack = Ticks - ticks;


ticks = Ticks;
for ( int i = 0; i < 1000; i++ )
Heap( );
heap = Ticks - ticks;


System.Windows.Forms.MessageBox.Show( "Stack\t: " + stack + "\nHeap\t: " + heap );
}
}
}

16 réponses

Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
Je viens de tester ton programme et il est vrai que l'allocation sur le
tas n'est pas aussi rapide que sur la pile (un facteur d'environ :
60)...



Mais moi j'aimerais savoir où est ce que tu as lu que l'allocation sur
le Heap était pratiquement aussi rapide que l'allocation sur la Pile en
.Net ??



Je ne m'y connais pas trop, mais je pense qu'en C/C++ c'est la même chose.... non ?

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Membre
Dernière intervention
30 octobre 2008
55
Meme reaction que ZogStrip, j'ai jamais lu que l'allocation sur le tas était aussi rapide que celui sur la pile.

Mx
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Salut, bien je ne sais plus ou j'ai lu ca à vrai dire.. On entend aussi parfois dire qu'avec les nouveaux microprocesseurs d'auourd'hui les différences ne sont plus aussi significatives.. En fait le but premier de ce test c'est que je voulais tester la performance du mot clé "stackalloc", non seulement c'est éfficace mais en plus le GC n'a aucun travail à faire à la sortie de la fonction et si je parcours le tableau avec le pointeur retourné je ne subit pas les ralentissement dû au tests "IndexOutOfRange" du "runtime". J'imagine que pour certaines applications ca peut êre utile..
Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
C'est certainement utile, mais ça voudrais dire que l'on retombe dans
des applications C/C++ alors que l'on code en C# et en Managé (et tout
le monde sait que Manage => Perte de performances....)

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Oui mais parfois travailler en unsafe c'est inévitable.. En général j'utilise plutôt Marshal.AllocCoTaskMem.. On peut aussi fixer en mémoire un tableau, mais je crois que c'est pas super performant.. Vi ok on retombe en C\C++ mais c'est une bonne réponse à ceux qui disent que le C# est pas rapide, qu'on peut pas faire de jeu ou ce genre d'application.. Il ne s'agit pas de tout coder en unsafe bien sûr, juste les parties critiques..
Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
Ouai je sais, et je pense que c'est pour cette raison que MS a laissé un moyen d'utiliser du code unsafe :)



Je ne m'y connais pas du tout en unsafe, est ce que tu pourrais expliquer ce que c'est : Marshal.AllocCoTaskMem ???



Merci

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
C'est comme malloc en C, tu alloues de la mémoire NON managée et donc tu peux y accéder avec un pointeur sans devoir la fixer, c'est pratique qu'en tu travailles avec PInvoke et que tu as besoin d'un buffer qui ne bouge pas en mémoire..
Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
Si je comprend bien c'est la version non managé de :



fixed(....) ???

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Pas vraiment, mais ca peut avoir la méme utilité, mais je n'imagine pas une application "fixer" un buffer durant tout le temps de son exécution.. de plus Microsoft préconise de fixer les objet le moins longtemps possible, surement pour ne pas bloquer le GC.
Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
Ben ouai, quand ont fixe un objet c'est qu'on a a pas besoin pour
longtemps, parce que ça empeche le Garbage Collector de le déplacé lors
de ces phases.. donc une perte de performance..

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Exactement.. avec Marshall.AllocCoTaskMem tu n'as pas se problème.
Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
J'ai ajouté à ton code la fonction :



private unsafe static void Test( )

{


System.Runtime.InteropServices.Marshal.AllocCoTaskMem(256 *
sizeof(byte));

}



Et je l'ai testé, mais pour mes tests c'est plus long que l'allocation sur le Heap en .Net....



Peut être que je me plante, c'est peut être pas : 256 * sizeof(byte)...





Testé grace au code suivant :



class Class1

{

[ System.Runtime.InteropServices.DllImport( "kernel32.dll" ) ]

[ System.Security.SuppressUnmanagedCodeSecurity ]

private static extern int QueryPerformanceCounter( ref long count );



private static long ticks = 0;



private static long Ticks

{

get

{

QueryPerformanceCounter( ref ticks );

return ticks;

}

}



private unsafe static void Stack( )

{

byte* p =
stackalloc byte[ 256 ]; // Attention à StackOverflowException.

}



private static void Heap( )

{

byte[ ] tab = new byte[ 256 ];

}



private unsafe static void Test( )

{


System.Runtime.InteropServices.Marshal.AllocCoTaskMem(256 *
sizeof(byte));

}



private static void Main( )

{

long ticks = 0;

long stack = 0;

long heap = 0;

long test = 0;



Stack( ); // JIT

Heap( ); // JIT

Test( ); // JIT



ticks = Ticks;

for ( int i = 0; i < 1000; i++ )

Stack( );

stack = Ticks - ticks;



ticks = Ticks;

for ( int i = 0; i < 1000; i++ )

Heap( );

heap = Ticks - ticks;



ticks = Ticks;

for( int i = 0; i < 1000; i++ )

Test( );

test = Ticks - ticks;




System.Console.WriteLine("Stack\t: " + stack + "\nHeap\t: " + heap +
"\nTest\t: " + test );

}

}

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Excuses moi j'avais pas vu ton message.. En fait pour faire une bonne utilisation de cette méthode, il faut s'en servir un seule fois dans ton code et garder le pointeur en champs de la classe.. Et n'oublie pas d'appeler Marshal.FreeCoTaskMem sinon bonjour le memory leak !

class App
{
private unsafe static byte* pBuffer = null;


private unsafe static void Main( )
{
pBuffer = ( byte* )Marshal.AllocCotaskMem( sizeof( byte ) * 256 );

// ...

Marshall.FreeCoTaskMem( ( IntPtr )pBuffer );
}
}
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Voilà un test plus significatif, avantage à Marshal.AllocCoTaskMem mais de peu.. Cela dit cette fonction reste utile pour PInvoke.

namespace Test
{
class App
{
[ System.Runtime.InteropServices.DllImport( "kernel32.dll" ) ]
[ System.Security.SuppressUnmanagedCodeSecurity ]
private static extern int QueryPerformanceCounter( out long count );


private static long ticks = 0;
private unsafe static byte* pBuffer = null;
private static byte[ ] buffer = null;


private static long Ticks
{
get
{
QueryPerformanceCounter( out ticks );
return ticks;
}
}


private unsafe static void Heap( )
{
fixed ( byte* p = buffer )
{
for ( int i = 0; i < 256; i++ )
p[ i ] = p[ i ]; // Read and Write
}
}


private unsafe static void Global( )
{
for ( int i = 0; i < 256; i++ )
pBuffer[ i ] = pBuffer[ i ]; // Read and write
}


private unsafe static void Main( )
{
pBuffer = ( byte* )Marshal.AllocCoTaskMem( sizeof( byte ) * 256 );
buffer = new byte[ 256 ];


long ticks = 0;
long heap = 0;
long global = 0;


Heap( ); // JIT
Global( ); // JIT


ticks = Ticks;
for ( int i = 0; i < 1000; i++ )
Heap( );
heap = Ticks - ticks;


ticks = Ticks;
for ( int i = 0; i < 1000; i++ )
Global( );
global = Ticks - ticks;


Marshal.FreeCoTaskMem( ( IntPtr )pBuffer );


System.Windows.Forms.MessageBox.Show( "Heap\t: " + heap + "\nGlobal\t: " + global );
}
}
}
Messages postés
164
Date d'inscription
dimanche 16 novembre 2003
Statut
Modérateur
Dernière intervention
5 juillet 2005
1
J'ai maintenant :



private unsafe static byte* pBuffer = null;

private unsafe static void Test( )

{

pBuffer =
(byte*)System.Runtime.InteropServices.Marshal.AllocCoTaskMem( sizeof(
byte ) * 256 );

System.Runtime.InteropServices.Marshal.FreeCoTaskMem((IntPtr) pBuffer);

}



Et c'est à peine plus rapide que le Heap...

Mais c'est plus rapide que ce que je faisais avant...



:p

ZogStriP
Mon Blog : IA pour Incomplet de l'Ancéphale Mon Site : Site web sur le projet [%3C/body ]
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Remarque c'est aussi le heap, le heap global.. Oui mais tu peux passer cette mémoire à du code NON managé c'est pratique.