[JAVA] Thread et mémoire

SuperCed

Membre expert
Club iGen
20 Juin 2001
1 328
70
44
superced.rb38.eu
Voilà, j'aimerais comprendre comment Java va gérer la mémoire dans ce cas présent.

j'ai une boucle dans ma classe principale sur le "main thread" :

Bloc de code:
public class MaClassePrincipale
public MaClassePrincipale() {
while(true) {
// fait des trucs
MyThread t = new MyThread();
// fait d'autres trucs
}
}
}
public static void main(String args[]) {
new MaClasserincipale();
}

Ma deuxième classe :
Bloc de code:
public class MyThread() implement Runnable() {
public MyThread() {
this.start();
}
public void run() {
//fait des machins
}
}

Je voudrais savoir si je vais saturer la mémoire avec ce genre de boucle ou pas d'une part?

D'autre part, je vais écraser la variable t à chaque itération.
Est-ce que ça va me poser de problème ou pas?
Est-ce que ça va effacer prématurément mon instance de classe MyThread?

Ou est-ce que ça ne pose aucun problème?

Sinon, je peux créer un tableau de MyThread, garder une référence sur chacune des instances. Puis en fin de script run, j'appelle une méthode sur ma classe principale qui met la référence à null dans mon tableau.

Qu'en pensez vous?

D'autre part, j'aimerais savoir si mon garbage collector va être appelé ou pas. J'ai un doute, car je fais une boucle sur la main thread et j'ai peur que le gc ne soit jamais appelé...
Dois-je le forcer à s'éxécuter?

Merci
 
Tu ferais mieux de nous dire plus précisément ce que tu veux faire, qu'on t'aide à le faire proprement. Là la création de thread dans une boucle infinie, ça parait douteux. D'un point de vue technique, t'appelles pas le run, donc les threads vont même pas être exécutés, ce sera que des objets instanciés qui n'auront tout de suite plus de références, donc qui devraient être détruits immédiatement, ou dès que le garbage collector en aura envie en tous cas.
Dans un usage normal, tu instancies tes threads, tu gardes des références dessus, et t'attends qu'ils se terminent avec un wait. D'un point de vue gestion de la mémoire, elle est désalouée quand le programme se termine, y compris dans les threads à priori, ou dès que t'auras plus de référence sur les objets. En java t'as pas à t'en préoccuper à priori, c'est sensé marcher tout seul. Sauf si t'as besoin d'optimiser les perfs, j'en connais qu'ont réécrit le garbage collector pour ça… Mais en général, le plus malin c'est de pas faire du java dans ces cas là.
 
Tu ferais mieux de nous dire plus précisément ce que tu veux faire, qu'on t'aide à le faire proprement. Là la création de thread dans une boucle infinie, ça parait douteux. D'un point de vue technique, t'appelles pas le run, donc les threads vont même pas être exécutés, ce sera que des objets instanciés qui n'auront tout de suite plus de références, donc qui devraient être détruits immédiatement, ou dès que le garbage collector en aura envie en tous cas.
Dans un usage normal, tu instancies tes threads, tu gardes des références dessus, et t'attends qu'ils se terminent avec un wait. D'un point de vue gestion de la mémoire, elle est désalouée quand le programme se termine, y compris dans les threads à priori, ou dès que t'auras plus de référence sur les objets. En java t'as pas à t'en préoccuper à priori, c'est sensé marcher tout seul. Sauf si t'as besoin d'optimiser les perfs, j'en connais qu'ont réécrit le garbage collector pour ça… Mais en général, le plus malin c'est de pas faire du java dans ces cas là.
J'appelle le run dans le créateur de mon objet MyThread.
this.start();
C'était donc bien ça ma question : dois-je garder des références sur mes instances de classe MyThread ou c'est Java qui gère tout seul ?

D'après s ce que je semble lire partout, l'instance semble gardée en mémoire même s'il n'y a pas de référence dans ma classe principale.

Par contre, je trouve que le code est assez clair pour comprendre ma question.

Je n'ai pas compris ta réponse Tatouille? Peux-tu étoffer un peu?
C'est le while infini qui te gène?
 
c'est d'une part ou tu while et d'autre part MyThread t = new MyThread(); qui devrait etre une collection de references, tu devrais avoir un pool de control pour tes threads eg maybe synchronized somewhere and something, pour moi tu leak et ca m'etonnerait que le gc de java soit plus intelligent qu un autre enfin c'est pas une histoire d'intelligence mais de fesabilite

http://oreilly.com/catalog/9780596007829/?CMP=AFC-ak_book&ATT=Java+Threads%2c+Third+Edition%2c

je pense que le ebook traine sur plein de site.
 
A priori, c'est pas la peine.

Le thread garde une référence sur lui même ce qui lui permet de ne pas être vidé par le gc.
Si j'avais besoin d'accéder à mon objet ensuite, alors une collection ou un Pool de threads serait intéressant, mais là, je n'y accéde pas ensuite et ils sont complètements indépendant de mon premier objet.

D'autre par, il n'y a pas de problème sur mon "while".

Le gestionnaire d'événement est utile si tu utilises une interface graphique. Dans mon cas, il s'agit juste d'un démon qui tourne tout seul.


En fait, dans mon while, j'ai un autre soket ouvert avec un readline qui permet de récupérer les événements réseaux.
Ce n'est donc pas génant, et je ne vais pas surcharger le processeur.

J'ai testé et ça a l'air de fonctionner finalement.
 
je ne sais pas c'est pas vision de faire quand je fais du multi-thread, comment tu as un controle sur les event networks? implemente ton run, je suis etonne que ta fronte loop ne surcharge pas le CPU

"Le thread garde une référence sur lui même ce qui lui permet de ne pas être vidé par le gc." oui mais un jours il faudra bien deferencer,

deadlock,
 
je ne sais pas c'est pas vision de faire quand je fais du multi-thread, comment tu as un controle sur les event networks? implemente ton run, je suis etonne que ta fronte loop ne surcharge pas le CPU

"Le thread garde une référence sur lui même ce qui lui permet de ne pas être vidé par le gc." oui mais un jours il faudra bien deferencer,

deadlock,

Non, ça ne sature pas le CPU, car je suis en attente d'événement réseau dans la boucle principale.
Donc ça bloque sur le "read" tant que rien n'est écrit sur le réseau.

Donc ça ne surcharge pas le processeur.

Pour ce qui est d'enlever la référence au thread, la JVM le fait lui même à la fin de son éxécution. Donc c'est bien foutu ce Java finalement.
 
(avais zappé le start, mais il manque peut-être un super dans le constructeur)
Ça risque de surcharger si tu reçois beaucoup d'événements réseaux non ? Habituellement on lance un nombre défini de thread, qui vont chacun traiter en boucle des événements réseaux quand il y en a (genre en les stockant dans une pile quand il n'y a pas de thread de dispo). Comme ça t'as toujours un nombre défini de thread, et t'es sûr que ça part pas en live.
 
(avais zappé le start, mais il manque peut-être un super dans le constructeur)
Ça risque de surcharger si tu reçois beaucoup d'événements réseaux non ? Habituellement on lance un nombre défini de thread, qui vont chacun traiter en boucle des événements réseaux quand il y en a (genre en les stockant dans une pile quand il n'y a pas de thread de dispo). Comme ça t'as toujours un nombre défini de thread, et t'es sûr que ça part pas en live.

Il n'y a pas de "super" car la classe n'hérite pas d'une autre classe.
Donc inutile de faire un super().

En ce qui concerne la gestion des threads, en efet, si tu en as beaucoup, il y a une classe spéciale qui gère ça en Java (voir java.util.concurrent.ExecutorService et import java.util.concurrent.Executors).

Ca permet de réutiliser les threads, de conserver une référence dessus, et de gérer une file d'attente.

Cependant, dans mon cas, je n'ai pas beaucoup de thread lancés en même temps. 3 au grand max, donc je n'ai pas ce type de problème.

Je l'ai testé et ça marche nickel.
 
Il n'y a pas de "super" car la classe n'hérite pas d'une autre classe.
Donc inutile de faire un super().

En ce qui concerne la gestion des threads, en efet, si tu en as beaucoup, il y a une classe spéciale qui gère ça en Java (voir java.util.concurrent.ExecutorService et import java.util.concurrent.Executors).

Ca permet de réutiliser les threads, de conserver une référence dessus, et de gérer une file d'attente.

Cependant, dans mon cas, je n'ai pas beaucoup de thread lancés en même temps. 3 au grand max, donc je n'ai pas ce type de problème.

Je l'ai testé et ça marche nickel.

Au temps pour moi, ça m'apprendra à lire en diagonale… ;) Bon du coup, si t'as tout testé et que ça marche très bien, où est la question ?
Et t'es sûr de pas rencontrer de problèmes plus tard, que le programme distant qui te génère les événements peut pas s'emballer ? Que le nombre d'événements peut pas être plus important dans 10 ans ? Qu'il faut pas que tu prévoies un mécanisme pour interrompre proprement le logiciel ? Je veux bien croire que ça convienne dans ton cas, mais n'empêche que ça me parait pas hyper clean.
 
Au temps pour moi, ça m'apprendra à lire en diagonale… ;) Bon du coup, si t'as tout testé et que ça marche très bien, où est la question ?
Et t'es sûr de pas rencontrer de problèmes plus tard, que le programme distant qui te génère les événements peut pas s'emballer ? Que le nombre d'événements peut pas être plus important dans 10 ans ? Qu'il faut pas que tu prévoies un mécanisme pour interrompre proprement le logiciel ? Je veux bien croire que ça convienne dans ton cas, mais n'empêche que ça me parait pas hyper clean.

Si ça marche déjà pendant 3 ans, c'est parfait.
Dans 10 ans, je pense que le besoin sera très très différent et qu'on aura tout recodé 4 fois déjà.
Ma question est en fait résolu.
Je voulais juste savoir si le gc ne vidait pas les threads qui n'avait plus de référence sur l'objet principal.
La réponse est non, quelqu'un m'a répondu sur MacBidouille.
 
Dans 10 ans, je pense que le besoin sera très très différent et qu'on aura tout recodé 4 fois déjà.

J'espère que t'en es bien sûr. ;) Parce que des bouts de codes conçus pour une démo où codés à l'arrache en vue d'être refaits plus tard, j'en ai déjà vu un paquet qu'étaient toujours là 15 ans plus tard. ;) En vertu du sacro-saint principe qui dit qu'on n'a jamais le temps de reprendre le code et qu'on préfère patcher et repatcher…
 
  • J’aime
Réactions: gKatarn
Tu peux utiliser des Thread pools, la création d'un Thread est assez couteuse, si tu peux les réutiliser, c'est mieux.
De plus, il est plutôt déconseillé de créer des Thread directement mais d'utiliser les nouvelles API Executor de Java 1.5. D'ailleurs, si tu es dans un environnement serveur, il est même interdit de créer des Thread.
Je te conseille aussi vivement la lecture de l'excellent Java Concurrency in Practice !
Il ne faut pas sous-estimer tous les problèmes qui viennent avec l'utilisation de concurrence et ce bouquin pourra te les montrer et te donner des solutions.
 
Tu peux utiliser des Thread pools, la création d'un Thread est assez couteuse, si tu peux les réutiliser, c'est mieux.
De plus, il est plutôt déconseillé de créer des Thread directement mais d'utiliser les nouvelles API Executor de Java 1.5. D'ailleurs, si tu es dans un environnement serveur, il est même interdit de créer des Thread.
Je te conseille aussi vivement la lecture de l'excellent Java Concurrency in Practice !
Il ne faut pas sous-estimer tous les problèmes qui viennent avec l'utilisation de concurrence et ce bouquin pourra te les montrer et te donner des solutions.

+100, e.g mon commentaire: je ne sais pas ce n'est pas ma facon de faire ...
 
D'autre part, j'aimerais savoir si mon garbage collector va être appelé ou pas. J'ai un doute, car je fais une boucle sur la main thread et j'ai peur que le gc ne soit jamais appelé...
Dois-je le forcer à s'éxécuter?

Merci

La JVM déclenche le GC si elle le peut et quand elle en a envie.
Si la boucle instanciait autre chose que des threads, tu aurais à chaque passage de ton MyThread t = new MyThread() un nouvel objet et un autre qui se retrouverait non référencé et donc eligible au GC.
Là, les threads ne sont pas dé-référencés donc pas eligibles au GC.

Ce n'est pas possible en Java de forcer l'exécution du GC.
 
oui mais comme dans d'autres languages tu peux signaler au GC qu'un objet doit etre planifié pour deletion,

[FONT=tahoma,arial,sans-serif][SIZE=-1]myObject = null;

[/SIZE][/FONT]
 
On est bien d'accord.
Il faut juste préciser que quand on fait :
Bloc de code:
MonObjet monObjet;  // crée un pointeur qui pointe sur rien
monObjet = new MonObjet(); // crée vraiment l'objet et donc aloue de la mémoire
monObjet = null; // déférence l'objet qui est seulement ELIGIBLE au GC mais qui n'est pas encore DETRUIT donc la mémoire n'est pas encore LIBEREE

=> éligible au GC ne veut pas dire que la mémoire est libérée.
Je sais que tu le sais, c'est juste pour être bien clair pour ceux qui débarquent sur Java.