J'ai une application qui lit un fichier CSV avec des piles de lignes de données. Je donne à l'utilisateur un résumé du nombre de lignes en fonction des types de données, mais je veux m'assurer de ne pas lire trop de lignes de données et de provoquer OutOfMemoryError
s. Chaque ligne se traduit par un objet. Existe-t-il un moyen simple de connaître la taille de cet objet par programme? Existe-t-il une référence qui définit la taille des types primitifs et des références d'objet pour un VM
?
En ce moment, j'ai du code qui dit lire jusqu'à 32 000 lignes , mais j'aimerais aussi avoir du code qui dit lire autant de lignes que possible jusqu'à ce que j'utilise 32 Mo de mémoire. C'est peut-être une question différente, mais j'aimerais quand même savoir.
Réponses:
Vous pouvez utiliser le package java.lang.instrument
Compilez et mettez cette classe dans un JAR:
Ajoutez ce qui suit à votre
MANIFEST.MF
:Utilisez getObjectSize:
Invoquer avec:
la source
byte[0]
,byte[1]
,byte[5]
,int[0]
,int[1]
,int[2]
selon l'approche que vous avez décrite? Ce serait bien, si les résultats incluent une surcharge pour la longueur du tableau et l'alignement de la mémoire.Vous devez utiliser jol , un outil développé dans le cadre du projet OpenJDK.
Pour obtenir les tailles des primitives, des références et des éléments de tableau, utilisez
VMSupport.vmDetails()
. Sur Oracle JDK 1.8.0_40 exécuté sur Windows 64 bits (utilisé pour tous les exemples suivants), cette méthode renvoieVous pouvez obtenir la taille superficielle d'une instance d'objet en utilisant
ClassLayout.parseClass(Foo.class).toPrintable()
(en passant éventuellement une instance àtoPrintable
). Il s'agit uniquement de l'espace consommé par une seule instance de cette classe; il n'inclut aucun autre objet référencé par cette classe. Il ne comprend de tête VM pour l' en- tête d'objet, l' alignement du champ et le rembourrage. Pourjava.util.regex.Pattern
:Vous pouvez obtenir une vue récapitulative de la taille profonde d'une instance d'objet à l'aide de
GraphLayout.parseInstance(obj).toFootprint()
. Bien sûr, certains objets de l'empreinte peuvent être partagés (également référencés à partir d'autres objets), il s'agit donc d'une surapproximation de l'espace qui pourrait être récupérée lorsque cet objet est récupéré. Pour le résultat dePattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")
(tiré de cette réponse ), jol rapporte une empreinte totale de 1840 octets, dont seulement 72 sont l'instance de Pattern elle-même.Si vous utilisez plutôt
GraphLayout.parseInstance(obj).toPrintable()
, jol vous indiquera l'adresse, la taille, le type, la valeur et le chemin des déréférences de champ à chaque objet référencé, bien que ce soit généralement trop de détails pour être utile. Pour l'exemple de modèle en cours, vous pouvez obtenir les éléments suivants. (Les adresses changeront probablement entre les exécutions.)Les entrées "(autre chose)" décrivent d'autres objets du tas qui ne font pas partie de ce graphique d'objet .
La meilleure documentation jol est les exemples jol dans le référentiel jol. Les exemples illustrent les opérations courantes de jol et montrent comment utiliser jol pour analyser les composants internes de VM et de garbage collector.
la source
vmDetails
c'est maintenantVM.current().details()
.GraphLayout.parseInstance(instance).toFootprint()
j'ai trouvé plus utile de comprendre la taille des objetsJ'ai accidentellement trouvé une classe java "jdk.nashorn.internal.ir.debug.ObjectSizeCalculator", déjà en jdk, qui est facile à utiliser et semble très utile pour déterminer la taille d'un objet.
résultats:
la source
ObjectSizeCalculator
n'est pris en charge que sur HotSpot VMIl y a quelques années, Javaworld avait un article sur la détermination de la taille des objets Java composites et potentiellement imbriqués , ils expliquent essentiellement la création d'une implémentation sizeof () en Java. L'approche s'appuie essentiellement sur d'autres travaux où les gens ont identifié expérimentalement la taille des primitives et des objets Java typiques, puis appliquent ces connaissances à une méthode qui parcourt récursivement un graphique d'objet pour calculer la taille totale.
Il sera toujours un peu moins précis qu'une implémentation C native simplement à cause des choses qui se passent dans les coulisses d'une classe, mais cela devrait être un bon indicateur.
Alternativement, un projet SourceForge appelé de manière appropriée sizeof qui offre une bibliothèque Java5 avec une implémentation sizeof ().
PS N'utilisez pas l'approche de sérialisation, il n'y a pas de corrélation entre la taille d'un objet sérialisé et la quantité de mémoire qu'il consomme lorsqu'il est en direct.
la source
Premièrement, "la taille d'un objet" n'est pas un concept bien défini en Java. Vous pourriez signifier l'objet lui-même, avec seulement ses membres, l'objet et tous les objets auxquels il fait référence (le graphique de référence). Vous pourriez signifier la taille en mémoire ou la taille sur le disque. Et la JVM est autorisée à optimiser des choses comme les chaînes.
Donc, la seule façon correcte est de demander à la JVM, avec un bon profileur (j'utilise YourKit ), ce qui n'est probablement pas ce que vous voulez.
Cependant, d'après la description ci-dessus, il semble que chaque ligne sera autonome et n'aura pas une grande arborescence de dépendances, donc la méthode de sérialisation sera probablement une bonne approximation sur la plupart des machines virtuelles Java. La façon la plus simple de procéder est la suivante:
N'oubliez pas que si vous avez des objets avec des références communes, cela ne donnera pas le résultat correct et la taille de la sérialisation ne correspondra pas toujours à la taille en mémoire, mais c'est une bonne approximation. Le code sera un peu plus efficace si vous initialisez la taille ByteArrayOutputStream à une valeur sensible.
la source
Si vous souhaitez simplement 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 car 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'utilise 32 Mo de mémoire."
la source
À l'époque où je travaillais sur Twitter, j'ai écrit un utilitaire pour calculer la taille d'un objet profond. Il prend en compte différents modèles de mémoire (32 bits, oups compressés, 64 bits), le remplissage, le remplissage de sous-classe, fonctionne correctement sur les structures de données circulaires et les tableaux. Vous pouvez simplement compiler ce 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
la source
La plupart des autres réponses fournissent des tailles superficielles - par exemple, la taille d'un HashMap sans aucune des clés ou des valeurs, ce qui n'est probablement pas ce que vous voulez.
Le projet jamm utilise le package java.lang.instrumentation ci-dessus mais parcourt l'arborescence et peut donc vous donner une utilisation approfondie de la mémoire.
https://github.com/jbellis/jamm
la source
Vous devez parcourir les objets en utilisant la réflexion. Soyez prudent lorsque vous faites:
byte
n'est pas est théoriquement 1 octet qu'il ne prend qu'un seul en mémoire.HashMap
ou un peu tel en utilisant object-equals comme comparateur pour éliminer les boucles infinies.@jodonnell: J'aime la simplicité de votre solution, mais de nombreux objets ne sont pas sérialisables (donc cela lèverait une exception), les champs peuvent être transitoires et les objets peuvent remplacer les méthodes standard.
la source
Vous devez le mesurer avec un outil, ou l'estimer à la main, et cela dépend de la JVM que vous utilisez.
Il y a une surcharge fixe par objet. Il est spécifique à JVM, mais j'évalue généralement 40 octets. Ensuite, vous devez regarder les membres de la classe. Les références d'objet sont de 4 (8) octets dans une machine virtuelle Java 32 bits (64 bits). Les types primitifs sont:
Les tableaux suivent les mêmes règles; c'est-à-dire qu'il s'agit d'une référence d'objet qui prend donc 4 (ou 8) octets dans votre objet, puis sa longueur multipliée par la taille de son élément.
Essayer de le faire par programme avec des appels à
Runtime.freeMemory()
ne vous donne pas beaucoup de précision, en raison d'appels asynchrones au garbage collector, etc. Le profilage du tas avec -Xrunhprof ou d'autres outils vous donnera les résultats les plus précis.la source
boolean[]
. En fait, toutes les primitives de type non double / long font 4 octets. Ces derniers sont 8 (la réponse les met à tort comme 4 aussi)La
java.lang.instrument.Instrumentation
classe fournit un bon moyen d'obtenir la taille d'un objet Java, mais elle vous oblige à définir unpremain
et à exécuter votre programme avec un agent java. Cela est très ennuyeux lorsque vous n'avez besoin d'aucun agent et que vous devez ensuite fournir un agent factice Jar à votre application.J'ai donc obtenu une solution alternative en utilisant la
Unsafe
classe dusun.misc
. Ainsi, en considérant l'alignement du tas d'objets selon l'architecture du processeur et le calcul du décalage de champ maximal, 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 à l'sun.misc.Unsafe
objet.la source
Il existe également l' outil Memory Measurer (anciennement chez Google Code , maintenant sur GitHub ), qui est simple et publié sous la licence commerciale Apache 2.0 , comme discuté dans une question similaire .
Il nécessite également un argument de ligne de commande à l'interpréteur java si vous voulez mesurer la consommation d'octets de mémoire, mais semble fonctionner correctement, au moins dans les scénarios que je l'ai utilisés.
la source
Sans avoir à vous soucier de l'instrumentation et ainsi de suite, et si vous n'avez pas besoin de connaître la taille exacte en octets d'un objet, vous pouvez opter pour l'approche suivante:
De cette façon, vous lisez la mémoire utilisée avant et après, et en appelant le GC juste avant d'obtenir la mémoire utilisée, vous réduisez le "bruit" presque à 0.
Pour un résultat plus fiable, vous pouvez exécuter votre travail n fois, puis diviser la mémoire utilisée par n, en obtenant la quantité de mémoire nécessaire pour une exécution. Encore plus, vous pouvez exécuter le tout plusieurs fois et faire une moyenne.
la source
System.gc()
informe- t-il pas simplement que vous souhaitez vous adresser au GC? Il n'est pas garanti que le GC soit appelé du tout.Voici un utilitaire que j'ai créé en utilisant certains des exemples liés pour gérer les bits 32, 64 et 64 bits avec la POO compressée. Il utilise
sun.misc.Unsafe
.Il utilise
Unsafe.addressSize()
pour obtenir la taille d'un pointeur natif etUnsafe.arrayIndexScale( Object[].class )
pour la taille d'une référence Java.Il utilise le décalage de champ d'une classe connue pour déterminer la taille de base d'un objet.
la source
Instrumentation
parce que je ne démarre pas tomcat,ObjectSizeCalculator
car je ne suis pas sûr du type de machine virtuelle (HotSpot) et desJOL
haricots de printemps bacouse. J'utilise ceci et j'ajoute un deuxième paramètre pour ignorer les singletons à savoirAbstractRefreshableApplicationContext.getBeanFactory().getSingletonMutex()
et leinternalSizeOf
code de refactor pour ignorer la classe et l'Je cherchais un calcul d'exécution d'une taille d'objet qui répondait aux exigences suivantes:
Ce qui suit est basé sur le code de base de l'article original des spécialistes java ( https://www.javaspecialists.eu/archive/Issue078.html ) et quelques bits de la version Unsafe dans une autre réponse à cette question.
J'espère que quelqu'un le trouvera utile.
}
la source
Il n'y a pas d'appel de méthode, si c'est ce que vous demandez. Avec un peu de recherche, je suppose que vous pourriez écrire le vôtre. Une instance particulière a une taille fixe dérivée du nombre de références et de valeurs primitives plus les données de tenue de livres d'instance. Vous parcourriez simplement le graphique d'objet. Moins les types de lignes sont variés, plus c'est facile.
Si c'est trop lent ou juste plus de problèmes que ça en vaut la peine, il y a toujours une bonne règle de comptage de lignes à l'ancienne.
la source
J'ai écrit une fois un test rapide pour estimer à la volée:
Le concept général consiste à allouer des objets et à mesurer les changements dans l'espace de mémoire libre. La clé étant
getFreeMemory()
, ce qui demande exécute GC et attend la taille de tas libre rapporté à se stabiliser . La sortie de ce qui précède est:C'est ce que nous attendons, compte tenu du comportement d'alignement et de la surcharge possible de l'en-tête du bloc de tas.
La méthode d'instrumentation détaillée dans la réponse acceptée ici est la plus précise. La méthode que j'ai décrite est précise mais uniquement dans des conditions contrôlées où aucun autre thread ne crée / supprime des objets.
la source
Utilisez simplement Java Visual VM.
Il a tout ce dont vous avez besoin pour profiler et déboguer les problèmes de mémoire.
Il dispose également d'une console OQL (Object Query Language) qui vous permet de faire beaucoup de choses utiles, dont l'une étant
sizeof(o)
la source
Lorsque vous utilisez JetBrains IntelliJ, activez d'abord "Attach memory agent" dans File | Paramètres | Construction, exécution, déploiement | Débogueur.
Lors du débogage, cliquez avec le bouton droit sur une variable d'intérêt et choisissez «Calculer la taille retenue»:
la source
Ma réponse est basée sur le code fourni par Nick. Ce code mesure la quantité totale d'octets qui sont occupés par l'objet sérialisé. Donc, cela mesure réellement les éléments de sérialisation + l'empreinte de la mémoire des objets simples (sérialisez simplement par exemple
int
et vous verrez que la quantité totale d'octets sérialisés ne l'est pas4
). Donc, si vous voulez que le numéro d'octet brut soit utilisé exactement pour votre objet - vous devez modifier un peu ce code. Ainsi:J'ai testé cette solution avec des types primitifs, String et sur certaines classes triviales. Il peut également ne pas y avoir de cas couverts.
MISE À JOUR: Exemple modifié pour prendre en charge le calcul de l'empreinte mémoire des objets du tableau.
la source
Vous pouvez générer un vidage de tas (avec jmap, par exemple), puis analyser la sortie pour trouver la taille des objets. Il s'agit d'une solution hors ligne, mais vous pouvez examiner les tailles peu profondes et profondes, etc.
la source
size vous donne l'augmentation de l'utilisation de la mémoire du jvm en raison de la création d'objet et c'est généralement la taille de l'objet.
la source
Cette réponse n'est pas liée à la taille de l'objet, mais lorsque vous utilisez un tableau pour héberger les objets; la quantité de mémoire qu'il allouera à l'objet.
Ainsi, les tableaux, la liste ou la carte de toutes ces collections ne stockeront pas vraiment les objets (uniquement au moment des primitives, la taille réelle de la mémoire des objets est nécessaire), elle ne stockera que les références de ces objets.
Maintenant le
Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection
PRIMITIVES
OBJETS
Je veux dire que tout l'objet REFERENCE n'a besoin que de 4 octets de mémoire. Il peut s'agir d'une référence de chaîne OU d'une référence d'objet double, mais cela dépend de la création de l'objet, la mémoire nécessaire variera.
eg) Si je crée un objet pour la classe ci-dessous,
ReferenceMemoryTest
alors 4 + 4 + 4 = 12 octets de mémoire seront créés. La mémoire peut différer lorsque vous essayez d'initialiser les références.Ainsi, lors de la création d'un tableau objet / référence, tout son contenu sera occupé par des références NULL. 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)
la source
Supposons que je déclare une classe nommée
Complex
comme:Afin de voir combien de mémoire est allouée aux instances actives de cette classe:
la source
Pour JSONObject, le code ci-dessous peut vous aider.
renvoie la taille en octets
Je l'ai vérifié avec mon objet JSONArray en l'écrivant dans un fichier. Il donne la taille d'un objet.
la source
Je doute que vous souhaitiez le faire par programme, sauf si vous voulez le faire une seule fois et le stocker pour une utilisation future. C'est une chose coûteuse à faire. Il n'y a pas d'opérateur sizeof () en Java, et même s'il y en avait un, il ne compterait que le coût des références à d'autres objets et la taille des primitives.
Une façon de le faire est de sérialiser la chose dans un fichier et de regarder la taille du fichier, comme ceci:
Bien sûr, cela suppose que chaque objet est distinct et ne contient pas de références non transitoires à autre chose.
Une autre stratégie serait de prendre chaque objet et d'examiner ses membres par réflexion et d'additionner les tailles (booléen & octet = 1 octet, court & char = 2 octets, etc.), en descendant dans la hiérarchie des membres. Mais c'est fastidieux et coûteux et finit par faire la même chose que la stratégie de sérialisation.
la source
java.lang.Integer
produit environ 80 octets, où la représentation en tas est généralement de 32 (contrairement à la représentation en flux d'objets, la représentation en tas dépend de la taille des pointeurs et de l'alignement des objets). En revanche, unenull
référence sérialisée nécessite un octet au lieu des quatre ou huit octets dans la mémoire de tas.