42 votes

Limitation de l'utilisation de la mémoire et du processeur d'un thread en Java?

Je suis en train d'écrire une application qui vous permettra d'avoir plusieurs threads en cours d'exécution, et l'envie d'étrangler le CPU/mémoire d'utilisation de ces fils.

Il y a une question similaire pour le C++, mais je veux essayer et d'éviter à l'aide de C++ et de la JNI, si possible. Je réalise que j'ai peut-être pas possible à l'aide d'un langage de plus haut niveau, mais je suis curieux de voir si quelqu'un a des idées.

EDIT: Ajout d'une prime; j'aimerais avoir quelques vraiment bons, bien pensé des idées sur ce.

EDIT 2: La situation dont j'ai besoin c'est de l'exécution d'autres personnes de code sur mon serveur. Fondamentalement, il est tout à fait arbitraire de code, avec la seule garantie qu'il y aura une méthode main sur le fichier de classe. Actuellement, plusieurs complètement classes disparates, qui sont chargés lors de l'exécution, sont en cours d'exécution simultanément comme des threads séparés.

La façon dont il est écrit, ce serait une douleur à refactoriser à créer des processus distincts pour chaque classe qui est exécutée. Si c'est le seul bon moyen de limiter l'utilisation de la mémoire via la VM arguments, alors ainsi soit-il. Mais je voudrais savoir si il existe un moyen de le faire avec les threads. Même en tant que processus distinct, j'aimerais être capable de quelque limiter son utilisation de l'UC, puisque comme je l'ai mentionné plus tôt, plusieurs de ces va être en cours d'exécution à la fois. Je ne veux pas une boucle infinie de porc de toutes les ressources.

EDIT 3: Un moyen facile de rapprocher la taille de l'objet est avec java de l' Instrumentation des classes; en particulier, la getObjectSize méthode. Notez qu'il y a quelque chose de configuration nécessaires à l'utilisation de cet outil.

32voto

kd304 Points 8369

Si je comprends votre problème, une solution serait de manière adaptative en sommeil le fils, de même que la lecture vidéo est fait en Java. Si vous savez que vous voulez de 50% d'utilisation du cœur, l'algorithme doit dormir environ 0,5 secondes, peut - être distribuées à l'intérieur d'une seconde (par exemple, 0,25 secondes de calcul, de 0,25 sec du sommeil, de l'e.t.c.). Voici un exemple de partir de mon lecteur vidéo.

long starttime = 0; // variable declared
//...
// for the first time, remember the timestamp
if (frameCount == 0) {
    starttime = System.currentTimeMillis();
}
// the next timestamp we want to wake up
starttime += (1000.0 / fps);
// Wait until the desired next time arrives using nanosecond
// accuracy timer (wait(time) isn't accurate enough on most platforms) 
LockSupport.parkNanos((long)(Math.max(0, 
    starttime - System.currentTimeMillis()) * 1000000));

Ce code va dormir sur la base des cadres/seconde valeur.

Pour limiter l'utilisation de la mémoire, vous pouvez envelopper votre création de l'objet dans une usine de méthode, et d'utiliser une sorte de sémaphore avec un nombre limité de permis octets de limiter le montant total estimé la taille de l'objet (vous devez estimer la taille de divers objets de rationner le sémaphore).

package concur;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class MemoryLimited {
    private static Semaphore semaphore = new Semaphore(1024 * 1024, true);
    // acquire method to get a size length array
    public static byte[] createArray(int size) throws InterruptedException {
        // ask the semaphore for the amount of memory
        semaphore.acquire(size);
        // if we get here we got the requested memory reserved
        return new byte[size];
    }
    public static void releaseArray(byte[] array) {
        // we don't need the memory of array, release
        semaphore.release(array.length);
    }
    // allocation size, if N > 1M then there will be mutual exclusion
    static final int N = 600000;
    // the test program
    public static void main(String[] args) {
        // create 2 threaded executor for the demonstration
        ExecutorService exec = Executors.newFixedThreadPool(2);
        // what we want to run for allocation testion
        Runnable run = new Runnable() {
            @Override
            public void run() {
                Random rnd = new Random();
                // do it 10 times to be sure we get the desired effect
                for (int i = 0; i < 10; i++) {
                    try {
                        // sleep randomly to achieve thread interleaving
                        TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10);
                        // ask for N bytes of memory
                        byte[] array = createArray(N);
                        // print current memory occupation log
                        System.out.printf("%s %d: %s (%d)%n",
                            Thread.currentThread().getName(),
                            System.currentTimeMillis(), array,
                            semaphore.availablePermits());
                        // wait some more for the next thread interleaving
                        TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10);
                        // release memory, no longer needed
                        releaseArray(array);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        // run first task
        exec.submit(run);
        // run second task
        exec.submit(run);
        // let the executor exit when it has finished processing the runnables
        exec.shutdown();
    }
}

5voto

Michael Borgwardt Points 181658

Vous pouvez obtenir beaucoup d'infos sur CPU et de la mémoire via JMX, mais je ne pense pas qu'il permet à toute la manipulation active.

Pour contrôler l'utilisation du PROCESSEUR à un certain degré, vous pouvez utiliser Thread.setPriority().

Comme pour la mémoire, il n'y a pas une telle chose comme par thread de la mémoire. Le concept même de threads Java moyens de mémoire partagée. Le seul moyen de contrôler l'utilisation de la mémoire via les options de ligne de commande comme -Xmx, mais il n'y a aucun moyen de manipuler les paramètres lors de l'exécution.

5voto

Andrew Points 8248

Entretien des forums Java . Fondamentalement, chronométrez votre exécution et attendez quand vous prenez trop de temps. Comme mentionné dans le thread d'origine, son exécution dans un thread séparé et l'interruption du thread de travail donneront des résultats plus précis, tout comme la moyenne des valeurs dans le temps.

 import java.lang.management.*;

ThreadMXBean TMB = ManagementFactory.getThreadMXBean();
long time = new Date().getTime() * 1000000;
long cput = 0;
double cpuperc = -1;

while(true){

if( TMB.isThreadCpuTimeSupported() ){
    if(new Date().getTime() * 1000000 - time > 1000000000){ //Reset once per second
    	time = new Date().getTime() * 1000000;
    	cput = TMB.getCurrentThreadCpuTime();
    }

    if(!TMB.isThreadCpuTimeEnabled()){
    	TMB.setThreadCpuTimeEnabled(true);
    }

    if(new Date().getTime() * 1000000 - time != 0)
    	cpuperc = (TMB.getCurrentThreadCpuTime() - cput) / (new Date().getTime() *  1000000.0 - time) * 100.0;  				
    }
//If cpu usage is greater then 50%
if(cpuperc > 50.0){
     //sleep for a little bit.
     continue;
}
//Do cpu intensive stuff
}
 

1voto

OscarRyz Points 82553

Vous pouvez affecter des priorités différentes pour les fils donc la plus pertinente thread obtenir prévue plus souvent.

Regardez cette réponse pour voir si cela aide.

Quand tout le thread en cours d'exécution ont la même priorité qu'ils peuvent fonctionner comme ceci:

t1, t2, t3,     t1, t2, t3,   t1, t2, t3

Lorsque vous affectez une priorité différente à l'un d'eux, il peut ressembler à:

t1, t1, t1, t1,    t2,    t1, t1, t1 t3.

Le premier thread s'exécute "le plus souvent" que le reste.

1voto

Peter Lawrey Points 229686

Si vous exécutez les threads d'un processus séparé vous pouvez le cap de l'utilisation de la mémoire et de limiter le nombre de Processeurs ou de modifier la priorité de ces fils.

Cependant, ce que vous faites est susceptible d'ajouter de la surcharge et de la complexité qui est souvent contre-productif.

Sauf si vous pouvez expliquer pourquoi vous voulez le faire (par exemple, vous avez un mal écrits de la bibliothèque vous n'avez pas confiance et ne peut pas obtenir de l'aide pour), je vous suggère de ne pas en avoir besoin.

La raison ce n'est pas facile de restreindre l'utilisation de la mémoire est il y a seulement un segment de mémoire partagée. Donc un objet qui est utilisé dans un thread est utilisable dans un autre et n'est pas affecté à un fil ou d'une autre.

La limitation d'utilisation de l'UC signifie l'arrêt de tous les fils de sorte qu'ils ne font rien, cependant une meilleure approche est de s'assurer que le fil ne perdez pas de CPU et ne sont actifs qu'en faisant le travail qui doit être fait, dans ce cas, vous ne voulez pas arrêter de le faire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X