`PhantomReachableExecutorService` is never cleaned up because its Cleaner action captures the wrapper
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 78/100
Direzione di ricerca
Inizia con PhantomReachableExecutorService e la registrazione closeWhenPhantomReachable mostrata nell’issue. Verifica come l’azione acquisisce il delegate, quindi cerca i test esistenti sulla pulizia dell’executor e sui riferimenti deboli. Il lavoro è completato quando il wrapper può essere raccolto e il suo executor arrestato dopo che il wrapper diventa irraggiungibile; la correzione suggerita non è stata compilata né eseguita.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Problem
PhantomReachableExecutorService is meant to shut down its executor once the wrapper is only phantom reachable.
It can't, because the action registered with the Cleaner holds a strong reference to the wrapper:
internal class PhantomReachableExecutorService(private val executorService: ExecutorService) :
ExecutorService {
init {
closeWhenPhantomReachable(this) { executorService.shutdown() }
}
Here executorService compiles to a read of the private property through this.
The generated lambda has a this$0 field, as javap -p -c 'com.openai.core.PhantomReachableExecutorService$1' shows on 4.49.0, 4.80.0 and 4.99.0:
final com.openai.core.PhantomReachableExecutorService this$0;
...
invokestatic com/openai/core/PhantomReachableExecutorService.access$getExecutorService$p
invokeinterface java/util/concurrent/ExecutorService.shutdown:()V
The Cleaner holds the action strongly, so the wrapper and its executor stay reachable for the life of the JVM.
Impact
ClientOptions.Builder.build() creates this wrapper by default, and streamHandlerExecutor(...) applies it to any ExecutorService.
So every client strands one wrapper and one ThreadPoolExecutor, whether or not it ever streams.
Calling close() shuts the pool down but doesn't release it.
This matters to applications that build clients repeatedly, for example one per tenant API key.
Reproduction
Build 2,000 sync and async client pairs, discard them, then take a class histogram with jcmd <pid> GC.class_histogram, which forces a full GC.
| Client setup | Retained PhantomReachableExecutorService |
|---|---|
| Default | 4,000 |
Default, calling close() on each client |
4,000 |
streamHandlerExecutor given a plain Executor |
0 |
Clients, sleepers and HTTP client wrappers were released in all three.
Suggested fix
Make the action capture the delegate rather than the wrapper, for example by registering it from a function that doesn't have this in scope, or by copying the delegate into a local first:
init {
val delegate = executorService
closeWhenPhantomReachable(this) { delegate.shutdown() }
}
This suggestion hasn't been compiled or run.
A regression test could register a wrapper, drop it, and assert through a WeakReference that it's collected after System.gc(), or that the delegate's isShutdown becomes true.
Workaround
Pass an Executor that isn't an ExecutorService to ClientOptions.Builder.streamHandlerExecutor(...).
- Lingua principale
- Kotlin
- Stelle
- 1.6k
- Fork
- 275
- Merge medio
- 13h 3m
- PR unite (30g)
- 174
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di openai/openai-java
-
HttpRequest.url() logs spaces in path segments as literal plus signsForse già presa @sylvesterkaczmarek l’ha presa 78 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
openai/openai-java#886 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Make diarized transcription duration and task optionalForse già presa @wskr00 l’ha presa 109 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
openai/openai-java#802 · 2 commenti · 3 reazioni ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 30/100
openai/openai-java#1175 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 Mezza giornata Idoneità per principianti 42/100
openai/openai-java#1160 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
openai/openai-java#956 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di openai/openai-java
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
AChep/keyguard-app#1665 ·
I maintainer di solito rispondono entro 1 giorno
-
bug 🐞 python 🐍
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
valkey-io/valkey-glide#7560 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
square/leakcanary#3022 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement impact:U1 P3 reach:R2 size:S
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
thtbee/nectarlink#196 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno