Mémoire consommée par un fil
J'ai besoin de surveiller la quantité de mémoire consommée par les fils engendré par mon application. L'idée est de prendre des mesures correctives, si un gourmand fil consomme trop de mémoire. J'ai évoqué les La quantité de mémoire mon fil de java?. L'une des suggestions sur ce lien est d'utiliser getThreadAllocatedBytes
dans ThreadMXBean.
j'ai expérimenté avec getThreadAllocatedBytes
avec le travail qui suit.
List<Long> primes = new ArrayList<Long>();
long i = 0;
while (true) {
primes.add(++i);
if ((i % 10) == 0) {
primes.clear();
System.runFinalization();
System.gc();
}
}
- Je exécuter ce travail sur les quatre threads pour un temps considérable. Bien que le travail ne s'accumule pas la mémoire en continu, les valeurs retournées par getThreadAllocatedBytes
ne cesse d'augmenter et de ne pas aller vers le bas encore une fois. Cela implique que getThreadAllocatedBytes
ne retourne pas le montant réel de la mémoire sur le tas utilisée par le thread. Il retourne la quantité totale de mémoire allouée sur le tas pour le filet, car il a été lancé. Ma plate-forme les détails sont comme suit:
Linux PG85213.egi.ericsson.com 3.5.0-030500-generic #201207211835 SMP Sam Juil 21 22:35:55 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, en mode mixte)
Est le comportement souhaité comportement de getThreadAllocatedBytes
?
Si oui, y a pas moyen de trouver efficace de la mémoire sur le tas utilisé par un fil.
Suis d'inscription le programme complet pour référence:
package workbench;
import java.lang.management.ManagementFactory;
import com.sun.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AnotherWorkBench {
private static final CountDownLatch latch = new CountDownLatch(4);
static final List<Long> threadIds = Collections.synchronizedList(new ArrayList<Long>());
private void dummyJob() {
List<Long> primes = new ArrayList<Long>();
long i = 0;
while (true) {
primes.add(++i);
if ((i % 10) == 0) {
primes.clear();
//introduce sleep to prevent process hogging
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(AnotherWorkBench.class.getName()).log(Level.SEVERE, null, ex);
}
System.runFinalization();
System.gc();
}
}
}
private void runDummyJobs() {
Runnable dummyJob = new Runnable() {
@Override
public void run() {
threadIds.add(Thread.currentThread().getId());
latch.countDown();
dummyJob();
}
};
Runnable memoryMonitorJob = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : Monitor thread started");
ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
threadMxBean.setThreadAllocatedMemoryEnabled(true);
while (true) {
for (Long threadId : threadIds) {
System.out.println(Thread.currentThread().getName() + " : Thread ID : " + threadId + " : memory = " + threadMxBean.getThreadAllocatedBytes(threadId) + " bytes");
}
//wait between subsequent scans
try {
System.out.println(Thread.currentThread().getName() + " : secondary sleep");
Thread.currentThread().sleep(5000);
System.out.println(Thread.currentThread().getName() + " : out of secondary sleep");
} catch (InterruptedException ex) {
Logger.getLogger(WorkBench.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
Executors.newSingleThreadExecutor().submit(dummyJob);
Executors.newSingleThreadExecutor().submit(dummyJob);
Executors.newSingleThreadExecutor().submit(dummyJob);
Executors.newSingleThreadExecutor().submit(dummyJob);
try {
latch.await();
} catch (InterruptedException ex) {
Logger.getLogger(AnotherWorkBench.class.getName()).log(Level.SEVERE, null, ex);
}
Executors.newSingleThreadExecutor().submit(memoryMonitorJob);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new AnotherWorkBench().runDummyJobs();
}
}
System.gc()
n' pas garantie que le GC est exécuté. Surtout dans votre cas, où System.gc()
est probablement appelé avec des sous-intervalles de millisecondes, la machine virtuelle peut décider de différer la GC exécuter pour certains arbitraire dans le temps; en général, lorsque la mémoire disponible est faible dans une certaine mesure.Pourriez-vous inclure un exemple plus complet s'il vous plaît, je voudrais répéter que votre expérience à l'échelle locale.
La SÈVE de la JVM (tools.hana.ondemand.com/#cloud) semble soutenir exactement cette fonction. Je n'ai jamais utilisé cette machine virtuelle, et de ne lire que c'est pris en charge.
OriginalL'auteur Sarveswaran Meenakshi Sundaram | 2014-07-30
Vous devez vous connecter pour publier un commentaire.
À ma connaissance, il n'existe aucun moyen fiable de le faire au moment de l'exécution. Et comme l'a souligné dans le question de départ, le tas est une ressource partagée, et donc la taille du tas d'un seul thread ne fait pas de sens qu'il va se chevauchent avec des références d'objet à partir d'autres threads.
Cela dit, quand je veux savoir la 'retenu' taille d'un seul fil, et oui conservé la taille est différente, mais de même métrique à celui que vous avez demandé, alors je le fais en prenant un tas de vidage, puis à l'aide de MAT (http://www.eclipse.org/mat/).
J'ai connu des gens à utiliser Java Agents à l'instrument, à la répartition des objets puis d'utiliser une référence faible pour surveiller lorsque il obtient GC. Cependant l'impact sur les performances de la faire, c'est de haut. Très haute.
Vous pouvez être le meilleur à l'aide d'une heuristique lors de l'exécution et les tests unitaires pour s'assurer que la mémoire reste dans des limites. Par exemple, vous pouvez utiliser JMX pour surveiller les tailles de tas et quand vous voyez le vieux gen croissante, alors vous pouvez déclencher une alerte. À l'aide de getThreadAllocatedBytes pour calculer les taux de répartition pourrait également être utile.
Bon moment de l'exécution des outils de surveillance: appdynamics, newrelic, visualvm et yourkit
Mode hors connexion pour la mémoire de l'analyse, mat et jclarity sont très bons.
Un outil très utile pour aider à un seul endroit, si il y a une fuite, ou, au moins, est en cours d'exécution différents des attentes est d'imprimer un décompte du nombre d'instances de chaque classe sont actuellement sur le tas: jcmd <pid> GC.class_histogram.
c'est exact, il n'existe pas de moyen de le faire. Et comme l'a souligné certaines des réponses, qu'est-ce que tas-mémoire consommée par thread " signifie réellement. Le tas est une ressource partagée, et un seul objet peut être accédé par plusieurs threads. C'est pourquoi j'ai mentionné " conservé de la taille, qui est une mesure qui peut être calculée soit en mode hors connexion ou lors de l'exécution. Cependant, à l'exécution, il en coûterait, et en fonction de comment vous l'avez fait inexacte. Hors ligne est la façon normale de faire, et des outils gratuits comme TAPIS de soutien. Les détails des deux sommes ci-dessus.
OriginalL'auteur Chris K
Java VisualVM peuvent être utilisés pour surveiller une application locale et de visualiser en temps réel, de données de haut niveau sur le segment de mémoire, le fil de l'activité, et les classes chargé dans la Machine Virtuelle Java (JVM). Suivi d'une application impose une faible surcharge et peut être utilisé pendant de longues périodes."
Voir aussi Comment surveiller Java utilisation de la mémoire?
pour d'autres possibilités.
si à l'aide de netbeans, il est en fait dans Netbeans Profiler, à droite? @DavidPostill ...
Aucune idée. Cette question n'a rien à voir avec Netbeans.
OriginalL'auteur DavidPostill