Java de tests unitaires: comment mesurer l'empreinte mémoire de l'appel de la méthode
En supposant que j'ai une classe qui fait une forte transformation, d'exploitation avec plusieurs collections. Ce que je veux faire est de s'assurer que cette opération ne peut pas conduire à l'extérieur de la mémoire ou même mieux, j'ai envie de mettre un seuil de combien de mémoire il peut utiliser.
class MyClass()
{
public void myMethod()
{
for(int i=0; i<10000000; i++)
{
//Allocate some memory, may be several collections
}
}
}
class MyClassTest
{
@Test
public void myMethod_makeSureMemoryFootprintIsNotBiggerThanMax()
{
new MyClass().myMethod();
//How do I measure amount of memory it may try to allocate?
}
}
Quelle est la bonne approche pour ce faire? Ou ce n'est pas possible/pas possible?
- P.: Arriver globale de l'utilisation de la mémoire ne vous autorise pas à dire ce que la mémoire a été utilisé pour.
- Yep, mais je peux définir l'exigence comme "cet algorithme ne doit pas consommer plus de 100 ko de RAM, ne doit pas dépendre de la taille des données à traiter". L'idée est de faire respecter ce par la création explicite de test de l'unité.
- Mais pourquoi souhaitez-vous créer une telle exigence? Les ressources sont à bas prix, Java est conçu en direction de ce fait. Vous ne devriez pas vous soucier de la consommation de mémoire jusqu'à ce que vous avez un problème réel. Autre que cela, même si vous trouvez un moyen de mesurer la mémoire, vous n'avez pas encore un moyen de mesure d'interpréter correctement les résultats et vous avez créé un réaliste de l'environnement de travail afin de produire des résultats plus réalistes. Il vous suffit de faire "un certain nombre" et de ne pas être plus sage, vraiment.
- Où est le mal si certains curieux dev est d'essayer de mesurer deux approches - t-il réaliste de travail env avant de faire tous les sens - je ne crois pas. Certaines approches prennent en général beaucoup moins de mémoire/CPU, ou les deux, dans quelque circonstance que les autres. Une telle analyse peut venir dans maniable pour au moins avoir une idée approximative.
- sont bon marché" est un peu présomptueux commentaire lorsque vous ne connaissez pas les infrastructures et la dotation budgétaire pour la solution
Vous devez vous connecter pour publier un commentaire.
Je peux penser à plusieurs options:
Vous pouvez également écrire votre propre test de référence qui compte à la mémoire. L'idée est de
System.gc()
,memoryBefore = runtime.totalMemory() - runtime.freeMemory()
System.gc()
,memoryAfter = runtime.totalMemory() - runtime.freeMemory()
C'est une technique que j'ai utilisé dans mon léger micro-outil de référence pour les qui est capable de mesurer l'allocation de mémoire avec l'octet de précision.
Vous pouvez utiliser le générateur de profils (par ex. JProfiler) pour afficher l'utilisation de la mémoire par les classes. Ou , comment mentionné Areo, il suffit d'imprimer l'utilisation de la mémoire:
Pour mesurer le courant de l'utilisation de la mémoire d'utilisation :
Runtime.getRuntime().freeMemory()
,Runtime.getRuntime().totalMemory()
Ici est un bon exemple:
obtenez de l'OS au niveau du système d'information
Mais cette mesure n'est pas précis, mais il peut vous donner beaucoup d'informations.
Un autre problème est avec
GC
qui est imprévisible.Voici un exemple de Netty qui fait quelque chose de similaire: MemoryAwareThreadPoolExecutor. La goyave est classe de cache a également basée sur la taille de l'expulsion. Vous pouvez consulter ces sources et de copier ce qu'ils font. En particulier, Voici comment Netty est l'estimation de l'objet tailles. En essence, vous feriez estimation de la taille des objets générés à l'aide de la méthode et de tenir un compte.
L'obtention de la mémoire globale de l'information (comme combien de tas est disponible) vous aidera à décider quelle quantité de mémoire à allouer à la méthode, mais de ne pas suivre la quantité de mémoire utilisée par les différents appels de méthode.
Cela dit, il est très rare que vous légitimement besoin de cela. Dans la plupart des cas, le plafonnement de l'utilisation de la mémoire en limitant le nombre d'objets peut être à un moment donné (par exemple en utilisant un délimitée de la file d'attente) est assez bonne, et il est beaucoup, beaucoup plus simple à mettre en œuvre.
Cette question est un peu délicate, en raison de la façon dont Java peut allouer beaucoup de courte durée de vie des objets en cours de traitement, qui seront ensuite recueillies lors de la collecte des ordures. Dans l'acceptation de réponse, nous ne pouvons pas dire avec certitude que la collecte des ordures a été exécutée à un moment donné. Même si nous introduisons une structure de boucle, avec de multiples
System.gc()
appels, la collecte des ordures pourrait fonctionner entre nos appels de méthode.Une meilleure façon est d'utiliser à la place une variante de ce qui est suggéré dans https://cruftex.net/2017/03/28/The-6-Memory-Metrics-You-Should-Track-in-Your-Java-Benchmarks.html, où
System.gc()
est déclenchée, mais nous avons également attendre que la signalées GC comte d'augmenter:Cela donne tout de même qu'une approximation de la mémoire allouée par votre code à un moment donné, mais la valeur est généralement beaucoup plus proche de ce que l'on peut généralement être intéressé par.