I ont la classe Collector
et ThreadLocalScope
comme ceci:mémoire ancienne génération augmente lors de l'utilisation ThreadLocal
Collector {
Collector() {
events = new LinkedList<>();
}
add(Event e) {
events.add(e);
}
flush() {
LinkedList<Event> copy = events;
new Thread(() -> {
for (Event e : copy) {
sendToServer(e);
}
copy.clear();
).start();
events = new LinkedList<>();
}
}
ThreadLocalScope {
public static ThreadLocal<Collector> local = new ThreadLocal<>() {
protected Collector initialValue() {
return new Collector();
}
}
}
Collector
ajoute simplement des événements et quand flush
est appelé envoie ces événements à une API dans un nouveau thread. Le Collector
est initialisé dans un ThreadLocal.
J'ai aussi une classe Job qui est exécutée plusieurs fois (en utilisant Quartz). Lorsque défini comme celui-ci tout fonctionne très bien:
Job {
execute() {
for (int i = 0; i < 100,000; i++) {
ThreadLocalScope.get().add(new Event());
}
ThreadLocalScope.get().flush();
}
}
Cependant, si au lieu que j'accrochons Collector comme ceci:
Job {
Collector collector;
Job() {
collector = ThreadLocalScope.get();
}
execute() {
for (int i = 0; i < 100,000; i++) {
collector.add(new Event());
}
collector.flush();
}
}
Je vois mon utilisation de la mémoire ancienne génération de plus en plus rapide et d'arrêt du monde cycles de collecte des ordures passe tout le temps. La seule différence est que j'ai ajouté Collector
comme variable membre plutôt que d'appeler ThreadLocalScope.get()
à chaque fois.
L'augmentation pourrait seulement signifier que les événements sont déplacés dans l'ancienne génération. Mais pourquoi cela arriverait-il? Collector
efface immédiatement toutes ses références aux événements, donc même si ce n'est pas GCed, les événements devraient être.
Chaque thread a donc sa propre instance de 'Collector'. Il ne peut y avoir aucune condition de course correcte? – dg428
oui Quartz réutilise le fil. Mais j'ai vérifié la création du travail et execute() fonctionne sur le même thread. Resuing Collector n'est pas un problème pour le prochain job car je peux effacer les évènements – dg428
Cependant, je pense que c'est à la racine de votre problème. Et pour être honnête, le thread local n'aide pas l'efficacité, et 'flush()' créer des threads comme ça est un gros coup de performance. –