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();
}
}
Notez que 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