Comment : utiliser Alloc et Free pour améliorer les performances de la mémoire
Ce document montre comment utiliser les fonctions concurrency ::Alloc et concurrency ::Free pour améliorer les performances de la mémoire. Il compare le temps nécessaire pour inverser les éléments d’un tableau en parallèle pour trois types différents qui spécifient chacun les opérateurs et delete
les new
opérateurs.
Les Alloc
fonctions et Free
les fonctions sont les plus utiles lorsque plusieurs threads appellent fréquemment à la fois Alloc
et Free
. Le runtime contient un cache de mémoire distinct pour chaque thread ; par conséquent, le runtime gère la mémoire sans utiliser de verrous ou de barrières de mémoire.
Exemple : types qui spécifient des opérateurs nouveaux et supprimés
L’exemple suivant montre trois types qui spécifient chacun les opérateurs et delete
les new
opérateurs. La new_delete
classe utilise les opérateurs et delete
les opérateurs globauxnew
, la malloc_free
classe utilise les fonctions malloc et free C Runtime, et la Alloc_Free
classe utilise le runtime Alloc
d’accès concurrentiel et Free
les fonctions.
// A type that defines the new and delete operators. These operators
// call the global new and delete operators, respectively.
class new_delete
{
public:
static void* operator new(size_t size)
{
return ::operator new(size);
}
static void operator delete(void *p)
{
return ::operator delete(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators
// call the C Runtime malloc and free functions, respectively.
class malloc_free
{
public:
static void* operator new(size_t size)
{
return malloc(size);
}
static void operator delete(void *p)
{
return free(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators
// call the Concurrency Runtime Alloc and Free functions, respectively.
class Alloc_Free
{
public:
static void* operator new(size_t size)
{
return Alloc(size);
}
static void operator delete(void *p)
{
return Free(p);
}
int _data;
};
Exemple : échanger et reverse_array fonctions
L'exemple suivant illustre les fonctions swap
et reverse_array
. La swap
fonction échange le contenu du tableau aux index spécifiés. Il alloue de la mémoire à partir du tas pour la variable temporaire. La reverse_array
fonction crée un grand tableau et calcule le temps nécessaire pour inverser ce tableau plusieurs fois en parallèle.
// Exchanges the contents of a[index1] with a[index2].
template<class T>
void swap(T* a, int index1, int index2)
{
// For illustration, allocate memory from the heap.
// This is useful when sizeof(T) is large.
T* temp = new T;
*temp = a[index1];
a[index1] = a[index2];
a[index2] = *temp;
delete temp;
}
// Computes the time that it takes to reverse the elements of a
// large array of the specified type.
template <typename T>
__int64 reverse_array()
{
const int size = 5000000;
T* a = new T[size];
__int64 time = 0;
const int repeat = 11;
// Repeat the operation several times to amplify the time difference.
for (int i = 0; i < repeat; ++i)
{
time += time_call([&] {
parallel_for(0, size/2, [&](int index)
{
swap(a, index, size-index-1);
});
});
}
delete[] a;
return time;
}
Exemple : fonction wmain
L’exemple suivant montre la wmain
fonction, qui calcule le temps nécessaire à la reverse_array
fonction pour agir sur le new_delete
, malloc_free
et Alloc_Free
les types, chacun utilisant un schéma d’allocation de mémoire différent.
int wmain()
{
// Compute the time that it takes to reverse large arrays of
// different types.
// new_delete
wcout << L"Took " << reverse_array<new_delete>()
<< " ms with new/delete." << endl;
// malloc_free
wcout << L"Took " << reverse_array<malloc_free>()
<< " ms with malloc/free." << endl;
// Alloc_Free
wcout << L"Took " << reverse_array<Alloc_Free>()
<< " ms with Alloc/Free." << endl;
}
Exemple de code complet
L’exemple complet suit.
// allocators.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <iostream>
using namespace concurrency;
using namespace std;
// Calls the provided work function and returns the number of milliseconds
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// A type that defines the new and delete operators. These operators
// call the global new and delete operators, respectively.
class new_delete
{
public:
static void* operator new(size_t size)
{
return ::operator new(size);
}
static void operator delete(void *p)
{
return ::operator delete(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators
// call the C Runtime malloc and free functions, respectively.
class malloc_free
{
public:
static void* operator new(size_t size)
{
return malloc(size);
}
static void operator delete(void *p)
{
return free(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators
// call the Concurrency Runtime Alloc and Free functions, respectively.
class Alloc_Free
{
public:
static void* operator new(size_t size)
{
return Alloc(size);
}
static void operator delete(void *p)
{
return Free(p);
}
int _data;
};
// Exchanges the contents of a[index1] with a[index2].
template<class T>
void swap(T* a, int index1, int index2)
{
// For illustration, allocate memory from the heap.
// This is useful when sizeof(T) is large.
T* temp = new T;
*temp = a[index1];
a[index1] = a[index2];
a[index2] = *temp;
delete temp;
}
// Computes the time that it takes to reverse the elements of a
// large array of the specified type.
template <typename T>
__int64 reverse_array()
{
const int size = 5000000;
T* a = new T[size];
__int64 time = 0;
const int repeat = 11;
// Repeat the operation several times to amplify the time difference.
for (int i = 0; i < repeat; ++i)
{
time += time_call([&] {
parallel_for(0, size/2, [&](int index)
{
swap(a, index, size-index-1);
});
});
}
delete[] a;
return time;
}
int wmain()
{
// Compute the time that it takes to reverse large arrays of
// different types.
// new_delete
wcout << L"Took " << reverse_array<new_delete>()
<< " ms with new/delete." << endl;
// malloc_free
wcout << L"Took " << reverse_array<malloc_free>()
<< " ms with malloc/free." << endl;
// Alloc_Free
wcout << L"Took " << reverse_array<Alloc_Free>()
<< " ms with Alloc/Free." << endl;
}
Cet exemple produit l’exemple de sortie suivant pour un ordinateur qui a quatre processeurs.
Took 2031 ms with new/delete.
Took 1672 ms with malloc/free.
Took 656 ms with Alloc/Free.
Dans cet exemple, le type qui utilise les Alloc
fonctions offre Free
les meilleures performances de mémoire, car les fonctions et Free
les Alloc
fonctions sont optimisées pour allouer et libérer fréquemment des blocs de mémoire à partir de plusieurs threads.
Compilation du code
Copiez l’exemple de code et collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé allocators.cpp
, puis exécutez la commande suivante dans une fenêtre d’invite de commandes Visual Studio.
cl.exe /EHsc allocators.cpp
Voir aussi
Fonctions de gestion de la mémoire
Alloc, fonction
Fonction libre