En Java, ce qui est la meilleure façon de déterminer la taille d'un objet?
Par exemple, disons que j'ai une application qui peut lire dans un fichier CSV avec des tas de lignes de données. Je donne à l'utilisateur un résumé du nombre de lignes basés sur les types de données, mais je veux m'assurer que je ne lis pas dans un trop grand nombre de lignes de données et de la cause OutOfMemoryError
s. Chaque ligne se traduit par un objet. Est-il un moyen facile de trouver de la taille de cet objet par programmation? Est-il un document de référence qui définit la façon dont les grands types primitifs et les références de l'objet sont pour une VM
?
Droit maintenant, j'ai un code qui dit lire jusqu'à 32 000 lignes, mais j'aimerais aussi avoir un code qui dit lire autant de lignes que possible jusqu'à ce que j'ai utilisé 32 MO de la mémoire. Peut-être que c'est une autre question, mais je voudrais encore savoir.
- J'ai ajouté mon Agent avec mvn configs, et explique comment ici: stackoverflow.com/a/36102269/711855
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser le java.lang.instrument paquet
De compiler et de mettre cette classe dans un BOCAL:
Ajouter les éléments suivants à votre
MANIFEST.MF
:Utilisation getObjectSize:
Invoquer avec:
byte[0]
,byte[1]
,byte[5]
,int[0]
,int[1]
,int[2]
l'utilisation de l'approche que vous avez décrit? Il serait bien, si les résultats comprennent les frais généraux pour la longueur du tableau et de l'alignement de la mémoire.byte[]
nombre de membres seulement comme un seul pointeur.Y a quelques années Javaworld avait un article sur la détermination de la taille de composite et potentiellement imbriquée des objets Java, ils se sont contentés de marcher à travers la création d'un sizeof() mise en œuvre en Java. L'approche s'appuie essentiellement sur d'autres travaux où les gens expérimentalement identifié la taille de primitives et typique des objets Java et ensuite d'appliquer ces connaissances à une méthode récursive de promenades d'un objet graphique compte de la taille totale.
Il va toujours être un peu moins précis qu'un natif C mise en œuvre simplement parce que de ce qui se passe derrière les coulisses d'une classe, mais il devrait être un bon indicateur.
À l'inverse, un projet sur SourceForge dûment appelé sizeof qui offre un Java5 bibliothèque avec un sizeof() de la mise en œuvre.
P. S. Ne pas utiliser la sérialisation approche, il n'y a pas de corrélation entre la taille d'un objet sérialisé et la quantité de mémoire qu'elle consomme quand live.
J'ai accidentellement trouvé une classe java
"jdk.nashorn.interne.ir.debug.ObjectSizeCalculator", déjà dans le jdk,
qui est facile à utiliser et semble tout à fait utile pour déterminer la taille d'un objet.
résultats:
ObjectSizeCalculator
est uniquement pris en charge sur les HotSpot VMTout d'abord "la taille d'un objet" n'est pas un concept défini dans Java. Vous pourrait signifier que l'objet lui-même, avec ses membres, l'Objet et tous les objets qu'il désigne (le graphique de référence). Vous pourriez dire la taille de la mémoire ou de la taille sur le disque. Et la JVM est autorisé à optimiser des choses comme des Chaînes de caractères.
Donc la seule possibilité est de demander à la JVM, avec un bon profiler (j'utilise YourKit), qui n'est probablement pas ce que vous voulez.
Cependant, à partir de la description ci-dessus, il sonne comme chaque ligne sera autonome et ne pas avoir une grande dépendance de l'arbre, de sorte que la méthode de sérialisation sera probablement une bonne approximation sur la plupart des machines virtuelles. La façon la plus simple de le faire est comme suit:
N'oubliez pas que si vous avez des objets avec des références communes cette ne donner le résultat correct, et la taille de la sérialisation pas toujours à la hauteur de la taille en mémoire, mais c'est une bonne approximation. Le code sera un peu plus efficace si vous utilisez le ByteArrayOutputStream une taille raisonnable de la valeur.
Si vous voudrais juste savoir combien de mémoire est utilisée dans votre JVM, et combien est libre, vous pouvez essayer quelque chose comme ceci:
edit: j'ai pensé que cela pourrait être utile que l'auteur de la question a également déclaré qu'il aimerait avoir une logique qui gère "lire autant de lignes que possible jusqu'à ce que j'ai utilisé de 32 mo de mémoire."
En arrière quand j'ai travaillé sur Twitter, j'ai écrit un utilitaire de calcul de la profondeur la taille de l'objet. Il prend en compte différents modèles de mémoire (32 bits, compressé oups, 64-bit), le rembourrage, la sous-classe de rembourrage, fonctionne correctement sur la circulaire de structures de données et des tableaux. Vous pouvez simplement compiler celui-ci .fichier java; il n'a pas de dépendances externes:
https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java
Beaucoup d'autres réponses fournissent peu profonde tailles - par exemple, la taille d'une table de hachage sans aucune des clés ou des valeurs, ce qui n'est probablement pas ce que vous voulez.
La jamm projet utilise le java.lang.instrumentation package ci-dessus, mais les promenades de l'arbre, et donc peut vous donner de la profondeur l'utilisation de la mémoire.
https://github.com/jbellis/jamm
Vous avez à marcher objets à l'aide de la réflexion. Veillez à ce que vous faites:
byte
est théoriquement 1 octet ne signifie pas qu'il suffit d'un seul dans la mémoire.HashMap
ou somesuch de l'objet est égale à la comparaison pour éliminer les boucles infinies.@jodonnell: j'aime la simplicité de votre solution, mais de nombreux objets ne sont pas Sérialisables (donc, ce serait jeter une exception), les champs peuvent être transitoires, et les objets peuvent remplacer les méthodes standard.
Vous devez le mesurer avec un outil, ou une estimation de main en main, et il dépend de la machine que vous utilisez.
Il y a certains frais fixes par objet. C'est la JVM, mais j'ai l'habitude de l'estimation de 40 octets. Ensuite, vous avez à regarder les membres de la classe. Les références de l'objet sont 4 (8) octets dans un 32 bits (64 bits) de la JVM. Les types primitifs sont:
Tableaux de suivre les mêmes règles; c'est, c'est un objet de référence qui prend 4 (ou 8) octets dans votre objet, puis à sa longueur multipliée par la taille de son élément.
Essayer de le faire par programmation avec des appels à
Runtime.freeMemory()
juste ne vous donne pas beaucoup de précision, en raison des appels asynchrones pour le garbage collector, etc. Profilage le tas avec -Xrunhprof ou d'autres outils vous donnera les résultats les plus précis.boolean[]
. En fait toutes les primitives non double/long types sont de 4 octets. Ces derniers sont des 8 (la réponse à tort met que 4 aussi)La
java.lang.instrument.Instrumentation
classe fournit un bon moyen pour obtenir la taille d'un Objet Java, mais il nécessite de définir unepremain
et exécuter votre programme avec java agent. C'est très ennuyeux quand vous n'avez pas besoin de tout agent et ensuite vous devez fournir un mannequin Pot de l'agent à votre demande.Donc j'ai une solution de rechange à l'aide de la
Unsafe
classe à partir de lasun.misc
. Donc, en considérant les objets de tas d'alignement en fonction de l'architecture du processeur et de calcul de la durée maximale du champ de décalage, vous pouvez mesurer la taille d'un Objet Java. Dans l'exemple ci-dessous, j'utilise une classe auxiliaireUtilUnsafe
pour obtenir une référence à lasun.misc.Unsafe
objet.Unsafe
méthode est mentionné sur: highlyscalable.wordpress.com/2012/02/02/... : il a "juste", lit-un objet interne du champ de longueur.Il y a aussi le Mémoire Mesureur de outil (anciennement à Google Code, maintenant sur GitHub), qui est simple et publié sous le commercial-friendly licence Apache 2.0, tel que discuté dans un question similaire.
Il nécessite également un argument de ligne de commande pour l'interprète de java si vous voulez mesurer la mémoire octet de la consommation, mais au contraire semble fonctionner très bien, au moins dans les scénarios que j'ai utilisé il.
Ici est un utilitaire que j'ai faite à l'aide de certains des exemples liés à la poignée 32-bit, 64-bit et 64-bits compressés de la programmation orientée objet. Il utilise
sun.misc.Unsafe
.Il utilise
Unsafe.addressSize()
pour obtenir la taille d'un pointeur natif etUnsafe.arrayIndexScale( Object[].class )
pour la taille de Java de référence.Il utilise le champ décalage d'une catégorie connue de travailler sur la base de la taille d'un objet.
Instrumentation
parce que je n'ai pas démarrer tomcat,ObjectSizeCalculator
car pas sûr de VM type(HotSpot) etJOL
bacouse beans spring. - Je l'utiliser et ajouter un second paramètre pour ignorer les singletons vizAbstractRefreshableApplicationContext.getBeanFactory().getSingletonMutex()
et refactoriserinternalSizeOf
code pour ignorer la Classe EnumSans avoir à jouer avec l'instrumentation et ainsi de suite, et si vous n'avez pas besoin de connaître les octets taille exacte d'un objet, vous pourriez aller avec l'approche suivante:
Cette façon de lire la mémoire utilisée avant et après, et l'appel de la GC juste avant d'arriver à la mémoire utilisée est de baisser le niveau de "bruit" presque à 0.
De plus pour un résultat fiable, vous pouvez exécuter votre travail n fois, et ensuite de diviser la mémoire utilisée par n, l'obtention de la quantité de mémoire une course. Même plus, vous pouvez exécuter l'ensemble de la chose plusieurs fois et faire une moyenne.
System.gc()
juste l'informer que vous souhaitez GC? Il n'est pas garanti que le GC est appelée à tous.Il n'y a pas un appel de méthode, si c'est ce que vous me demandez. Avec un peu de recherche, je suppose que vous pourriez écrire votre propre. Un cas particulier est fixe de taille moyenne dérivée à partir du nombre de références et de valeurs primitives plus d'instance tenue de la comptabilité de données. Vous pouvez tout simplement marcher sur le graphe d'objets. Le moins varié les types de ligne, le plus facile.
Si c'est trop lent ou tout simplement plus d'ennuis que cela vaut la peine, il y a toujours de la bonne vieille ligne de comptage de règle-de-pouce.
J'ai écrit un test rapide une fois pour estimer à la volée:
Concept général consiste à allouer des objets et de mesurer le changement dans l'espace de segment de mémoire. La clé étant
getFreeMemory()
, qui demandes GC s'exécute et attend que la signalées libre de la taille du segment de stabiliser. La sortie de la ci-dessus est:Qui est ce que nous attendons, compte tenu de l'alignement de comportement et possible segment en-tête du bloc des frais généraux.
L'instrumentation de la méthode détaillée dans l'acceptation de réponse ici les plus précis. La méthode que j'ai décrite est exact mais seulement dans des conditions contrôlées où aucun autre thread n'création/jetant des objets.
Suffit d'utiliser java visual VM.
Il a tout ce dont vous avez besoin pour le profil et le débogage des problèmes de mémoire.
Il dispose également d'un OQL (Object Query Language) console qui permet de faire beaucoup de choses utiles, dont un
sizeof(o)
Ma réponse est basée sur le code fourni par Nick. Ce code mesures montant total d'octets occupés par l'objet sérialisé. Si cette mesure en réalité la sérialisation des trucs + plaine de l'objet de la mémoire (juste sérialiser par exemple
int
et vous verrez que le montant total de sérialisé octets n'est pas4
). Donc, si vous voulez obtenir raw nombre d'octet utilisé exactement pour votre objet, vous devez modifier le code un peu. Comme:J'ai testé cette solution avec les types primitifs, de la Corde, et sur certains trivial classes. Il y a peut-être pas couvertes cas aussi.
Mise à JOUR: Exemple modifié pour prendre en charge la mémoire de calcul de l'empreinte de la matrice des objets.
Vous pouvez générer un dump du tas (avec jmap, par exemple), puis d'analyser la sortie de trouver l'objet tailles. C'est une solution hors ligne, mais vous pouvez examiner profonde et peu profonde tailles, etc.
taille vous donne l'augmentation de l'utilisation de la mémoire de la jvm en raison de la création de l'objet et que, généralement, est la taille de l'objet.
Cette réponse n'est pas liée à la taille de l'Objet, mais quand vous êtes en utilisant un tableau pour contenir les objets; la quantité de mémoire de la taille, il va allouer pour l'objet.
Donc des tableaux, une liste ou une carte de tous ceux de la collection ne sera pas aller afin de stocker des objets vraiment (uniquement au moment de primitives, véritable objet de la taille de la mémoire est nécessaire), il va stocker uniquement les références de ces objets.
Maintenant la
Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection
PRIMITIVES
OBJETS
Je veux dire tous les objets de RÉFÉRENCE avec 4 octets de mémoire. Il est peut-être la Chaîne de référence OU Double référence de l'objet, Mais cela dépend de la création d'un objet de la mémoire nécessaire varie.
e.g) Si je créer un objet pour le dessous de la classe
ReferenceMemoryTest
alors 4 + 4 + 4 = 12 octets de mémoire sera créé. La mémoire peut varier lorsque vous essayez d'initialiser les références.Donc lors de la création de l'objet/référence tableau, tout son contenu sera occupé avec des références NULLES. Et nous savons que chaque référence nécessite 4 octets.
Et enfin, l'allocation de mémoire pour le code ci-dessous est de 20 octets.
ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); ( 4(ref1) + 12 = 16 octets)
ReferenceMemoryTest ref2 = ref1; ( 4(ref2) + 16 = 20 octets)
Supposons que je déclare une classe nommée
Complex
comme:Afin de voir la quantité de mémoire allouée à vivre les instances de cette classe:
Je cherchais un moteur d'exécution de calcul de la taille de l'objet qui satisfait aux exigences suivantes:
La liste suivante est basée sur le code de base de l'original java spécialistes de l'article (https://www.javaspecialists.eu/archive/Issue078.html) et quelques brèves de l'Dangereux version dans une autre réponse à cette question.
J'espère que quelqu'un le trouve utile.
}
Pour JSONObject le code ci-dessous peut vous aider.
retourne la taille en octets
Je l'ai vérifié avec mon JSONArray objet par écrit dans un fichier. C'est en donnant la taille de l'objet.
Je doute que vous voulez le faire par programmation sauf si vous voulez juste faire une fois et de les stocker pour une utilisation future. C'est un coûteuse. Il n'y a pas de sizeof() opérateur en Java, et même s'il y était, il ne serait que de compter le coût des références vers d'autres objets et la taille de l'primitives.
D'une manière que vous pourriez faire c'est de sérialiser la chose à un Fichier et regarde la taille du fichier, comme ceci:
Bien sûr, cela suppose que chaque objet est distinct et ne contient pas non transitoire des références à autre chose.
Une autre stratégie serait de prendre chaque objet et de l'examiner ses membres par la réflexion et à ajouter les tailles (boolean & octet = 1 byte, short & char = 2 octets, etc.), travailler votre chemin vers le bas de l'adhésion de la hiérarchie. Mais c'est fastidieux et coûteux, et finit par faire la même chose, la sérialisation stratégie permettrait de le faire.
java.lang.Integer
produit environ 80 octets, où le tas de représentation est généralement 32 (contrairement aux flux d'objet de représentation, le tas de représentation dépend de pointeur de tailles et d'alignement d'objets). En revanche, un sérialisénull
de référence nécessite un octet au lieu de quatre ou huit octets dans la mémoire de masse.