[External] : Re: Virtual thread memory leak because TrackingRootContainer keeps threads

Michal Domagala outsider404 at gmail.com
Tue Jul 9 15:54:22 UTC 2024


Could you explain the "closeable queue"? Indeed, I want "close" queue and
my implementation is

> queueMap.remove(customerId)


I was sure my solution is genius rather than obscure :)
But I would like to learn another way to achieve closeable queue

wt., 9 lip 2024 o 17:43 Robert Engels <robaho at icloud.com> napisał(a):

> As an aside, that seems like a much more complicated and obscure design
> than using closable queues.
>
> On Jul 9, 2024, at 10:24 AM, Michal Domagala <outsider404 at gmail.com>
> wrote:
>
> Indeed, for 25+ years thread is GC root.
> But for 3+ years virtual threads are present and they are documented as
> ephemeral.
> Developers are used to alive threads and virtual, alive threads are not
> confusing. But virtual, alive threads documented as ephemeral are confusing.
> Moreover, the idea that VT from Executors API is GCed but from Thread API
> not looks inconsistent. But it is low confusion. Working against
> documentation is high confusion.
>
> Let's consider my case. I take 1000 Kafka events for concrete people each
> poll. 90% of events are ignored (not my customers), 10% are processed (my
> customers), but each event must be acked.
> Each customer has a blocking queue. 10% is distributed to proper queues.
> Each queue has a VT, which processes the event and finally ack the event.
> From time to time customers are off. Their blocking queues are thrown
> away.
> There is a chance that at the same moment the customer is off, new poll
> come with customer events. Kafka listener put event to customer queue and
> expects VT will ack the event.
> VT can't be stopped by the "customer-off" process, because new events may
> come to the blocking queue anytime.
>
> Race can be solved without synchronization. GC "knows" when the blocking
> queue is not visible by Kafka listener thread and "stops" the VT by
> reclaiming its resources.
>
> I hope this example is clear enough to see that reclaiming VT resources by
> GC is simple and automatic when manual solution requires thread
> synchronization and is prone to errors.
>
> wt., 9 lip 2024 o 16:24 Alan Bateman <Alan.Bateman at oracle.com> napisał(a):
>
>> On 09/07/2024 12:51, Michal Domagala wrote:
>> > Thanks for valuable observability context
>> >
>> > As I understand, initially VT created by Thread API was not observable
>> > in thread dump and VT created by Executors API was observable. It was
>> > confusing and now both kinds of VT are observable. Make sense.
>> > But observability is reached by strong reference. VT created by Thread
>> > API are strongly referenced until stop and not GC'ed until stop and VT
>> > created by Executors API are not referenced at all and GC'ed when not
>> > reachable, regardless of being stopped or not. That's not OK and much
>> > worse than previous confusion.
>>
>> An ExecutorService implementation has to keep a reference to each
>> task/thread because of the shutdownNow and close method. There are other
>> thread groupings that arise when using structured concurrency that
>> require a thread executing a main task wait for threads executing
>> subtasks to finish executing.
>>
>> As things stand I don't expect there will be much confusion. For 25+
>> years, a started thread is alive (and strongly reachable) until it
>> terminates. Having virtual thread work mostly the same shouldn't be a
>> surprise. As I said, the door hasn't been closed on introducing some
>> notion of ephemeral thread in the future. It's not really feasible right
>> now because of finalization and because of several issues related to
>> cleaner actions and explicit APIs to keep some object reachable until a
>> thread gets to some point in its execution. So there is more to this
>> than just observability (and yes of course observability could traverse
>> other reference types if needed).
>>
>> As regards the thread counting in the root container when running with
>> the undocumented system property jdk.trackAllThreads is set to false.
>> That is the count of the live (started but not terminated) threads in
>> that thread grouping. It is a left over from when we will mulling over
>> what the right default should be (reporting a thread count when you
>> can't list the threads has some value).
>>
>> -Alan
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20240709/4c9f6b4f/attachment.htm>


More information about the loom-dev mailing list