Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-06-22 Thread Tony Printezis
Can I also add that, when a buffer in the cache needs to be replaced with a
new (and typically larger) one, the old buffer is explicitly freed. So, the
code already assumes that buffers that are in the cache should not be
reachable from anywhere else. Explicitly freeing them when the thread exits
is consistent (IMHO) with this behavior.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 22, 2018 at 7:11:05 AM, Alan Bateman (alan.bate...@oracle.com)
wrote:

On 21/06/2018 21:13, Florian Weimer wrote:
> * Tony Printezis:
>
>> There are a few obvious ways to mitigate this, e.g., cause a Full GC /
>> concurrent GC cycle at regular intervals. However, the best solution
IMHO
>> is to explicitly free any direct buffers that are still in the cache
when a
>> thread exits.
> Why is this safe? Couldn't these direct byte buffers be used with a
> custom channel that leaks them to another thread?
The temporary direct buffer mechanism is internal to java.base so it
should never be used with custom channel implementations. There may be
some pre-existing issues with the FileChannel transferXXX methods when
called with an untrusted source/sink that will need to be audited but
this is not something that I can discuss on this mailing list.

-Alan


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-21 Thread Tony Printezis
Peter,

The changes to TestMaxCachedBufferSize.java look fine. One point though:
Why do you need the TmpDirectBuffersReclamation.java test? In
TestMaxCachedBufferSize.java you just call checkDirectBuffers(0, 0); after
you the main thread calls join() on the workers?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 1:29:38 PM, Peter Levart (peter.lev...@gmail.com) wrote:



On 06/21/2018 07:01 PM, Tony Printezis wrote:

I’m trying exactly that. :-)


Sorry, I didn't know. Here's my attempt:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.07/

I also added @run main/othervm to TempDirectBuffersReclamation test.

Peter



—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 12:59:58 PM, Peter Levart (peter.lev...@gmail.com)
wrote:



On 06/21/2018 06:17 PM, Tony Printezis wrote:

I was saying: I looked at TestMaxCachedBufferSize and, unfortunately, I
don’t think the test makes a lot of sense right now as it checks the number
/ size of direct buffers after all the threads terminate and, with this
change, that should always be 0.


You're right. The test makes no sense now. As I understand, the test
checked that number/size of allocated temporary buffers did not exceed the
estimated calculated size by checking the MXBean immediately after threads
terminate. This will never happen after the change as they will all be
freed before checking, regardless of how many were and how much was
allocated.

Perhaps the test should be modified to include a latch so that threads wait
until the measurement is made and only then are allowed to exit...

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-21 Thread Tony Printezis
I’m trying exactly that. :-)


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 12:59:58 PM, Peter Levart (peter.lev...@gmail.com)
wrote:



On 06/21/2018 06:17 PM, Tony Printezis wrote:

I was saying: I looked at TestMaxCachedBufferSize and, unfortunately, I
don’t think the test makes a lot of sense right now as it checks the number
/ size of direct buffers after all the threads terminate and, with this
change, that should always be 0.


You're right. The test makes no sense now. As I understand, the test
checked that number/size of allocated temporary buffers did not exceed the
estimated calculated size by checking the MXBean immediately after threads
terminate. This will never happen after the change as they will all be
freed before checking, regardless of how many were and how much was
allocated.

Perhaps the test should be modified to include a latch so that threads wait
until the measurement is made and only then are allowed to exit...

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-21 Thread Tony Printezis
…and I also hadn’t attached the test. Sorry, I’m clearly very distracted
today!


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 12:17:57 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

(I unfortunately pressed Send accidentally; apologies)

I was saying: I looked at TestMaxCachedBufferSize and, unfortunately, I
don’t think the test makes a lot of sense right now as it checks the number
/ size of direct buffers after all the threads terminate and, with this
change, that should always be 0.

Let me look into this and I’ll get back to you in a bit.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 12:14:24 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

Attached TerminatingThreadLocalTest.java. Let me know what you think (and
feel free to modify it / discard it if you don’t like it!).

Re: The test for the max cached buffer size is:
test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java. I looked at it and,
unfortunately,


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 7:07:59 AM, Peter Levart (peter.lev...@gmail.com) wrote:



On 06/20/2018 04:24 PM, Tony Printezis wrote:

Hey Peter,

I had written a test to test my version of the exit hooks. I can easily
rework it to work with yours. Interested?


Of course. Just give what you got. I can modify it as needed.


To check that the native buffers are reclaimed promptly, we should be able
to amend the test that tests the setting of the max size for the cached
buffers (i.e., check that, after all the threads have exited, the total
native count / size is 0).


Good idea. Do you happen to know which one is it?


Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 20, 2018 at 10:08:48 AM, Peter Levart (peter.lev...@gmail.com)
wrote:


On 06/18/2018 05:41 PM, Alan Bateman wrote:
>
>
> On 17/06/2018 22:20, Peter Levart wrote:
>> Update: the discussion on concurrent-interest about possible future
>> addition of public ThreadLocal.getIfPresent() or
>> ThreadLocal.isPresent() has died out, but it nevertheless reached a
>> point where ThreadLocal.isPresent() was found the least problematic.
>> So I would like to get further with this proposal using the last
>> webrev.04 version of the patch that uses ThreadLocal.isPresent()
>> internally - still package-private at the moment.
>>
>> Here's the webrev (unchanged from the day it was published):
>>
>> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/
>>
>> Would this version be OK?
> I think looks quite good.
>
> One small nit is that the update to ThreadLocal.setInitialValue makes
> it look like all locals are registered when setting the initial value.
> What would you think about moving the instanceof check from
> TerminatingThreadLocal.register so that it's a bit more obvious.
>
> -Alan

Like the following?

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.05/


Do we need a test which proves that cached direct buffers are released
when thread exits or would a unit test for TerminatingThreadLocal be
enough? Maybe both?

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-21 Thread Tony Printezis
(I unfortunately pressed Send accidentally; apologies)

I was saying: I looked at TestMaxCachedBufferSize and, unfortunately, I
don’t think the test makes a lot of sense right now as it checks the number
/ size of direct buffers after all the threads terminate and, with this
change, that should always be 0.

Let me look into this and I’ll get back to you in a bit.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 12:14:24 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

Attached TerminatingThreadLocalTest.java. Let me know what you think (and
feel free to modify it / discard it if you don’t like it!).

Re: The test for the max cached buffer size is:
test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java. I looked at it and,
unfortunately,


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 7:07:59 AM, Peter Levart (peter.lev...@gmail.com) wrote:



On 06/20/2018 04:24 PM, Tony Printezis wrote:

Hey Peter,

I had written a test to test my version of the exit hooks. I can easily
rework it to work with yours. Interested?


Of course. Just give what you got. I can modify it as needed.


To check that the native buffers are reclaimed promptly, we should be able
to amend the test that tests the setting of the max size for the cached
buffers (i.e., check that, after all the threads have exited, the total
native count / size is 0).


Good idea. Do you happen to know which one is it?


Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 20, 2018 at 10:08:48 AM, Peter Levart (peter.lev...@gmail.com)
wrote:


On 06/18/2018 05:41 PM, Alan Bateman wrote:
>
>
> On 17/06/2018 22:20, Peter Levart wrote:
>> Update: the discussion on concurrent-interest about possible future
>> addition of public ThreadLocal.getIfPresent() or
>> ThreadLocal.isPresent() has died out, but it nevertheless reached a
>> point where ThreadLocal.isPresent() was found the least problematic.
>> So I would like to get further with this proposal using the last
>> webrev.04 version of the patch that uses ThreadLocal.isPresent()
>> internally - still package-private at the moment.
>>
>> Here's the webrev (unchanged from the day it was published):
>>
>> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/
>>
>> Would this version be OK?
> I think looks quite good.
>
> One small nit is that the update to ThreadLocal.setInitialValue makes
> it look like all locals are registered when setting the initial value.
> What would you think about moving the instanceof check from
> TerminatingThreadLocal.register so that it's a bit more obvious.
>
> -Alan

Like the following?

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.05/


Do we need a test which proves that cached direct buffers are released
when thread exits or would a unit test for TerminatingThreadLocal be
enough? Maybe both?

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-21 Thread Tony Printezis
Peter,

Attached TerminatingThreadLocalTest.java. Let me know what you think (and
feel free to modify it / discard it if you don’t like it!).

Re: The test for the max cached buffer size is:
test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java. I looked at it and,
unfortunately,


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 21, 2018 at 7:07:59 AM, Peter Levart (peter.lev...@gmail.com) wrote:



On 06/20/2018 04:24 PM, Tony Printezis wrote:

Hey Peter,

I had written a test to test my version of the exit hooks. I can easily
rework it to work with yours. Interested?


Of course. Just give what you got. I can modify it as needed.


To check that the native buffers are reclaimed promptly, we should be able
to amend the test that tests the setting of the max size for the cached
buffers (i.e., check that, after all the threads have exited, the total
native count / size is 0).


Good idea. Do you happen to know which one is it?


Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 20, 2018 at 10:08:48 AM, Peter Levart (peter.lev...@gmail.com)
wrote:


On 06/18/2018 05:41 PM, Alan Bateman wrote:
>
>
> On 17/06/2018 22:20, Peter Levart wrote:
>> Update: the discussion on concurrent-interest about possible future
>> addition of public ThreadLocal.getIfPresent() or
>> ThreadLocal.isPresent() has died out, but it nevertheless reached a
>> point where ThreadLocal.isPresent() was found the least problematic.
>> So I would like to get further with this proposal using the last
>> webrev.04 version of the patch that uses ThreadLocal.isPresent()
>> internally - still package-private at the moment.
>>
>> Here's the webrev (unchanged from the day it was published):
>>
>> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/
>>
>> Would this version be OK?
> I think looks quite good.
>
> One small nit is that the update to ThreadLocal.setInitialValue makes
> it look like all locals are registered when setting the initial value.
> What would you think about moving the instanceof check from
> TerminatingThreadLocal.register so that it's a bit more obvious.
>
> -Alan

Like the following?

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.05/


Do we need a test which proves that cached direct buffers are released
when thread exits or would a unit test for TerminatingThreadLocal be
enough? Maybe both?

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-20 Thread Tony Printezis
Hey Peter,

I had written a test to test my version of the exit hooks. I can easily
rework it to work with yours. Interested?

To check that the native buffers are reclaimed promptly, we should be able
to amend the test that tests the setting of the max size for the cached
buffers (i.e., check that, after all the threads have exited, the total
native count / size is 0).

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 20, 2018 at 10:08:48 AM, Peter Levart (peter.lev...@gmail.com)
wrote:


On 06/18/2018 05:41 PM, Alan Bateman wrote:
>
>
> On 17/06/2018 22:20, Peter Levart wrote:
>> Update: the discussion on concurrent-interest about possible future
>> addition of public ThreadLocal.getIfPresent() or
>> ThreadLocal.isPresent() has died out, but it nevertheless reached a
>> point where ThreadLocal.isPresent() was found the least problematic.
>> So I would like to get further with this proposal using the last
>> webrev.04 version of the patch that uses ThreadLocal.isPresent()
>> internally - still package-private at the moment.
>>
>> Here's the webrev (unchanged from the day it was published):
>>
>> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/
>>
>> Would this version be OK?
> I think looks quite good.
>
> One small nit is that the update to ThreadLocal.setInitialValue makes
> it look like all locals are registered when setting the initial value.
> What would you think about moving the instanceof check from
> TerminatingThreadLocal.register so that it's a bit more obvious.
>
> -Alan

Like the following?

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.05/


Do we need a test which proves that cached direct buffers are released
when thread exits or would a unit test for TerminatingThreadLocal be
enough? Maybe both?

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-19 Thread Tony Printezis
Good idea, as long as it re-uses the existing ThreadLocal infrastructure
and doesn’t introduce an extra per-thread map. Making it a ThreadLocal
subclass would be an excellent start.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 19, 2018 at 9:07:07 AM, David Lloyd (david.ll...@redhat.com) wrote:

It may be confusing (to some, I guess) but it is consistent: the
ThreadLocal subclass author has absolute control over how the value is
presented to the user. Adding compute() or many of the other
suggested variants will break that guarantee, which seems like kind of
a big deal to me.

What about introducing a different thread local API that has more
modern behavior? Maybe a new subclass of ThreadLocal?

On Mon, Jun 18, 2018 at 5:28 PM Martin Buchholz 
wrote:
>
> yes, the proposed new methods would use nulls differently. The original
get() behavior of creating a mapping was a mistake, inconsistent with Map.
Yes, it will cause confusion. But it's already confusing.
>
> On Mon, Jun 18, 2018 at 1:45 PM, David Lloyd 
wrote:
>>
>> On Mon, Jun 18, 2018 at 12:53 PM, Martin Buchholz 
wrote:
>> > On Mon, Jun 18, 2018 at 10:21 AM, Tony Printezis <
tprinte...@twitter.com>
>> > wrote:
>> >
>> >> Martin,
>> >>
>> >> You are forgiven. :-)
>> >>
>> >> So, the (valid, I think) issue with getIfPresent(), as originally
proposed
>> >> by Peter, was that if get() was overridden in the subclass to somehow
>> >> transform the returned value, getIfPresent() wouldn’t apply the same
>> >> transformation.
>> >>
>> >> Doesn’t your compute() method have essentially the same issue? Apart
from
>> >> that, I personally like this proposal as I agree: one look-up is
always
>> >> better than two.
>> >>
>> >>
>> > A non-prototype implementation would delegate compute into
ThreadLocalMap
>> > itself, where there is no risk of overriding.
>>
>> I don't think overriding is the risk; the risk would be compute*
>> behaving inconsistently with regards to an overridden get*.
>>
>>
>> --
>> - DML
>
>


-- 
- DML


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-18 Thread Tony Printezis
Martin,

You are forgiven. :-)

So, the (valid, I think) issue with getIfPresent(), as originally proposed
by Peter, was that if get() was overridden in the subclass to somehow
transform the returned value, getIfPresent() wouldn’t apply the same
transformation.

Doesn’t your compute() method have essentially the same issue? Apart from
that, I personally like this proposal as I agree: one look-up is always
better than two.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 18, 2018 at 10:13:02 AM, Martin Buchholz (marti...@google.com)
wrote:

I'm ignoring the direct buffers problem (sorry Tony) and wearing my
ReentrantReadWriteLock hat.  I still like the idea of adding
ThreadLocal.compute(Function remappingFunction) and perhaps other such
map-inspired methods. RRWL wouldn't benefit much, since it already tries to
minimize use of ThreadLocal, but it would at least allow get() and remove()
to be coalesced on read-unlock.

RRWL never changes from one non-null value to another, it only switches
between absent and present.  I'd like to avoid the two lookups due to get
and remove.  Here's a prototype that does not yet help RRWL, but helps
callers switching between non-null values, and could probably be extended
via surgery to ThreadLocalMap:

public T compute(
java.util.function.Function
remappingFunction) {
final Thread currentThread = Thread.currentThread();
final ThreadLocalMap map = getMap(currentThread);
final ThreadLocalMap.Entry e = (map == null)
? null
: map.getEntry(this);
final T oldValue = (e == null) ? null : (T)e.value;
final T newValue = remappingFunction.apply(oldValue);
if (newValue == null) {
if (oldValue != null) {
map.remove(this);
}
} else if (e != null) {
e.value = newValue;
} else if (map != null) {
map.set(this, newValue);
} else {
createMap(currentThread, newValue);
}
return newValue;
}



On Sun, Jun 17, 2018 at 2:20 PM, Peter Levart 
wrote:

> Update: the discussion on concurrent-interest about possible future
> addition of public ThreadLocal.getIfPresent() or ThreadLocal.isPresent()
> has died out, but it nevertheless reached a point where
> ThreadLocal.isPresent() was found the least problematic. So I would like to
> get further with this proposal using the last webrev.04 version of the
> patch that uses ThreadLocal.isPresent() internally - still package-private
> at the moment.
>
> Here's the webrev (unchanged from the day it was published):
>
> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/
>
> Would this version be OK?
>
> Regards, Peter
>
>
>
> On 06/06/18 20:55, Peter Levart wrote:
>
>


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-07 Thread Tony Printezis
Peter,

Inline.


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 7, 2018 at 5:21:43 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi Tony,

Thanks for taking a look. Just a couple of comments inline...

On 06/06/18 22:38, Tony Printezis wrote:


- instead of overriding initialValue(), ThreadLocal.setInitialValue() calls
TerminatingThreadLocal.register() at the right moment


Thanks. I much prefer not having to introduce calculateInitialValue().

One extra suggestion: Given you introduced a call to TerminatingThreadLocal
from ThreadLocal, would it make sense to maybe do the same for set() and
remove() (you’d have to add an appropriate check in unregister) and not
override them in TerminatingTreadLocal? I totally get why you might not
want to do that (an extra check when a ThreadLocal is not the Terminating
one). I’m OK either way.


Yes, precisely. My 1st version did just that, but since there are usages of
ThreadLocal out there that are very performance sensitive, I opted for an
approach where there is zero performance regression for
non-TerminatingThreadLocal(s) when calling set() or remove(). A call-back
from setInitialValue is not so problematic as it usually occurs just once
per thread, but I can imagine a scenario where calls to get() and set()
occur very rapidly.


Yeah, I agree that this is a good trade-off given how the code is currently
structured.





An alternative to "T getIfPresent()" is a "boolean isPresent()" method.
Even if it remains package-private, with such method TerminatingThreadLocal
could be implemented as:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/

If TreadLocal.isPresent() was made public, the code could be further
simplified.


Something like:

if (tl.isPresent()) {

   T val = t.get();

   ….

}

will do two look-ups if the value exists. However, that’s better than
allocating unnecessarily. So, I’ll take isPresent() over not having a way
to check whether a value exists.


Right, and in our scenario, it is just isPresent() that is called for every
termination of every thread (REGISTRY.isPresent()). .get() is then called
only when there's actually something to do.


Yes. I’m not worried about that at all.




Thumbs up from me.


Let's just wait for a day or two to see whether the discussion on
concurrency-interest gives us any additional ideas. Currently I'm thinking
of proposing the addition of isPresent() API. As far as this RFR is
concerned, I'm consequently promoting the latest webrev.04.


Again, #ThumbsUp from me. Thanks,


Tony



So any comments on that one? Alan?

Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-06 Thread Tony Printezis
Hi Peter,

Thanks for the updated webrev! Please see inline.


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 6, 2018 at 2:55:51 PM, Peter Levart (peter.lev...@gmail.com) wrote:

Ok, here's next webrev:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.03/

The changes from webrev.02 are:

- renamed JdkThreadLocal -> TerminatingThreadLocal


#ThumbsUp



- instead of overriding initialValue(), ThreadLocal.setInitialValue() calls
TerminatingThreadLocal.register() at the right moment


Thanks. I much prefer not having to introduce calculateInitialValue().

One extra suggestion: Given you introduced a call to TerminatingThreadLocal
from ThreadLocal, would it make sense to maybe do the same for set() and
remove() (you’d have to add an appropriate check in unregister) and not
override them in TerminatingTreadLocal? I totally get why you might not
want to do that (an extra check when a ThreadLocal is not the Terminating
one). I’m OK either way.



- TerminatingThreadLocal.threadTerminated() now takes a (T value) parameter


#ThumbsUp



- TerminatingThreadLocal.REGISTRY uses IdentityHashSet instead of HashSet
(if .equals()/.hashCode() are overriden in some TerminatingThreadLocal
subclass)


#ThumbsUp



David Lloyd has commented on concurrency-interest about
ThreadLocal.getIfPresent(). There is a concern that such new method would
be inconsistent with what ThreadLocal.get() returns from existing
ThreadLocal subclasses that override .get() and possibly transform the
value returned from super.get() on the way.


That’s a very good point.



An alternative to "T getIfPresent()" is a "boolean isPresent()" method.
Even if it remains package-private, with such method TerminatingThreadLocal
could be implemented as:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.04/

If TreadLocal.isPresent() was made public, the code could be further
simplified.


Something like:

if (tl.isPresent()) {

   T val = t.get();

   ….

}

will do two look-ups if the value exists. However, that’s better than
allocating unnecessarily. So, I’ll take isPresent() over not having a way
to check whether a value exists.


Thumbs up from me.


Tony



Regards, Peter


On 06/06/18 18:58, Peter Levart wrote:



On 06/06/18 17:41, Tony Printezis wrote:

Peter,

You’re totally right re: JdkThreadLocal::initialValue being final and
cannot be overridden (I had completely missed the final keyword when I
first looked at the webrev). But it’d be nice to have the same API in both
versions of ThreadLocal. I assume you didn’t want to override get() since
you only wanted to update the REGISTRY the first time get() is called by a
thread. If getIfPresent() is exposed, would something like the following
work?

@Override
public T get() {
final T value = getIfPresent();
if (value != null) {
return value;
}
REGISTRY.get().add(this);
return super.get();
}


This would work, but if mapped value was 'null', it would keep calling
REGISTRY.get().add(this) for each get(). Logically correct, but with
useless overhead.

 Let me try to do something that might satisfy you... (in next webrev).


One more question re: getIfPresent() (and maybe I’m overthinking this): It
returns null to indicate that a value is not present. Isn’t null a valid
ThreadLocal value? Would using an Optional here be more appropriate?


The problem with Optional is that it does not provide an additional value.
Optional.empty() is a replacement for null. There's no Optional.of(null).
So what would getIfPresent() return when there was a mapping present, but
that mapping was null?

Regards, Peter


Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 6, 2018 at 11:12:44 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi Tony, Alan,

On 06/06/2018 04:37 PM, Tony Printezis wrote:

Alan,

Thanks for your thoughts!

Peter,

Any chance of taking the two suggestions I made in an earlier e-mail into
account?


Right, I'll prepare new webrev with that shortly.


a) It’d be nice if users can override initialValue(), like when using the
standard ThreadLocal class, instead of calculateInitialValue(). (I can’t
come up with a clean solution on how to do that, though. I’ll think about
it for a bit.)


Your concern was that users might accidentally override initialValue()
instead of calculateInitialValue(), if I understood you correctly. If that
was the concern, they can't, because it is final. If the concern was that
users would want to override initialValue() because they are used to do so,
then perhaps a javadoc on final initialiValue() pointing to
calculateInitialValue() might help them. Do you agree? This is currently
internal API and consistent naming is not a big concern.

b) It’d be very helpful to pass T value to threadTerminated(), as I cannot
imagine many use-cases where the value will not be needed.


Agree. Will incl

Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-06 Thread Tony Printezis
Peter,

You’re totally right re: JdkThreadLocal::initialValue being final and
cannot be overridden (I had completely missed the final keyword when I
first looked at the webrev). But it’d be nice to have the same API in both
versions of ThreadLocal. I assume you didn’t want to override get() since
you only wanted to update the REGISTRY the first time get() is called by a
thread. If getIfPresent() is exposed, would something like the following
work?

@Override
public T get() {
final T value = getIfPresent();
if (value != null) {
return value;
}
REGISTRY.get().add(this);
return super.get();
}

One more question re: getIfPresent() (and maybe I’m overthinking this): It
returns null to indicate that a value is not present. Isn’t null a valid
ThreadLocal value? Would using an Optional here be more appropriate?

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 6, 2018 at 11:12:44 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi Tony, Alan,

On 06/06/2018 04:37 PM, Tony Printezis wrote:

Alan,

Thanks for your thoughts!

Peter,

Any chance of taking the two suggestions I made in an earlier e-mail into
account?


Right, I'll prepare new webrev with that shortly.


a) It’d be nice if users can override initialValue(), like when using the
standard ThreadLocal class, instead of calculateInitialValue(). (I can’t
come up with a clean solution on how to do that, though. I’ll think about
it for a bit.)


Your concern was that users might accidentally override initialValue()
instead of calculateInitialValue(), if I understood you correctly. If that
was the concern, they can't, because it is final. If the concern was that
users would want to override initialValue() because they are used to do so,
then perhaps a javadoc on final initialiValue() pointing to
calculateInitialValue() might help them. Do you agree? This is currently
internal API and consistent naming is not a big concern.

b) It’d be very helpful to pass T value to threadTerminated(), as I cannot
imagine many use-cases where the value will not be needed.


Agree. Will include that in new webrev.


Re: renaming JdkThreadLocal: ThreadLocalWithExitHooks?


Hm. Exit Hooks are already something that is used in JVM (Threads started
when VM is about to exit), so this might be confusing for someone.

- DisposableThreadLocal
- ThreadLocalWithCleanup

And my favorite:

- TerminatingThreadLocal



Re: exposing getIfPresent() : Yes! Pretty please! :-) This will be very
helpful and can avoid completely unnecessary allocations.


I agree that this would be generally useful functionality. Might be good to
ask for opinion on concurrency-interest mailing list first. Will do that.

Regards, Peter


Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 6, 2018 at 9:38:05 AM, Alan Bateman (alan.bate...@oracle.com) wrote:



On 30/05/2018 22:16, Peter Levart wrote:
> I thought there would be some hint from Alan about which of the two
> paths we should take for more refinement.
>
> The Tony's:
>
> http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/
>
> Or the Alan's with my mods:
>
> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.02/
>
Finally getting back to this one.

I don't think the two approaches are all that different now. Tony's
point on the number of hooks vs. number of locals was an important point
but with Peter's update to use a thread local registry then I think we
have easy to maintain solution in the DBBCache_Cleanup/webrev.02 patch.
So I think I prefer that approach. We need to better name for
"JdkThreadLocal", something to indicate that it holds resources or it
notified when a thread terminates.

Also along the way, we touched on exposing getIfPresent and we should
look at that again. If it is expose then it fits well with the second
approach too.

-Alan


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-06 Thread Tony Printezis
Alan,

Thanks for your thoughts!

Peter,

Any chance of taking the two suggestions I made in an earlier e-mail into
account?

a) It’d be nice if users can override initialValue(), like when using the
standard ThreadLocal class, instead of calculateInitialValue(). (I can’t
come up with a clean solution on how to do that, though. I’ll think about
it for a bit.)
b) It’d be very helpful to pass T value to threadTerminated(), as I cannot
imagine many use-cases where the value will not be needed.

Re: renaming JdkThreadLocal: ThreadLocalWithExitHooks?

Re: exposing getIfPresent() : Yes! Pretty please! :-) This will be very
helpful and can avoid completely unnecessary allocations.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On June 6, 2018 at 9:38:05 AM, Alan Bateman (alan.bate...@oracle.com) wrote:



On 30/05/2018 22:16, Peter Levart wrote:
> I thought there would be some hint from Alan about which of the two
> paths we should take for more refinement.
>
> The Tony's:
>
> http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/
>
> Or the Alan's with my mods:
>
> http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.02/
>
Finally getting back to this one.

I don't think the two approaches are all that different now. Tony's
point on the number of hooks vs. number of locals was an important point
but with Peter's update to use a thread local registry then I think we
have easy to maintain solution in the DBBCache_Cleanup/webrev.02 patch.
So I think I prefer that approach. We need to better name for
"JdkThreadLocal", something to indicate that it holds resources or it
notified when a thread terminates.

Also along the way, we touched on exposing getIfPresent and we should
look at that again. If it is expose then it fits well with the second
approach too.

-Alan


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-06-05 Thread Tony Printezis
Hey Alan,

Any thoughts on this? (with apologies for the ping)

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 30, 2018 at 5:16:44 PM, Peter Levart (peter.lev...@gmail.com) wrote:

I thought there would be some hint from Alan about which of the two paths
we should take for more refinement.

The Tony's:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/

Or the Alan's with my mods:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.02/


Regards, Peter


On 05/30/18 22:46, Tony Printezis wrote:

Hi all,

Any more thoughts on this? (with apologies for the ping)

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 18, 2018 at 3:58:57 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Hi again,

Stylistically, I strongly prefer this version over the previous one (the
one with the doubly-linked list of JdkThreadLocal entries) you had posted.
This one is a lot cleaner.

A few suggestions:

* I’m not crazy about the fact that the users have to override
calculateInitialValue() instead of initialValue() as it will be a bit
error-prone. If they accidentally override initialValue() then the
per-thread registering is not going to happen. Maybe I’m overthinking this.
One way to get round this is for each JdkThreadLocal instance to delegate
calls to get(), set(), and remove() to a private ThreadLocal instance,
which can in turn delegate initialValue() to the outer instance. (Hope this
makes sense?) I did a quick prototype of this and it seems to work, but I
didn’t heavily test it.

* I would prefer if the method users override actually took the
thread-local value as a parameter, i.e., protected void threadTerminated(T
value). This is very easy to add:

protected void threadTerminated(T value) {
}

private void threadTerminated() {
threadTerminated(get());
}

and I think it will be easier to use, as most uses will probably need to do
get() anyway.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 18, 2018 at 4:23:19 AM, Peter Levart (peter.lev...@gmail.com) wrote:

It's good to have alternative implementations on the table. Here's another
variant that is space neutral for threads that don't use JdkThreadLocal,
but also scales to many JdkThreadLocal instances:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.02/

Now we only need an arbiter to decide which one! :-)

Regards, Peter

On 05/17/18 22:39, Peter Levart wrote:

Hi Tony,

If we anticipate only small number of JdkThreadLocal(s) (there will be only
one for the start) then this is a plausible solution. Then perhaps this
limitation should be written somewhere in the JdkThreadLocal javadoc so
that one day somebody will not be tempted to use JdkThreadLocal(s) en
masse. Let's say there will be a few more JdkThreadLocal(s) in the future.
Are we willing to pay for a few lookups into a ThreadLocalMap at each and
every thread's exit even though such thread did not register a mapping for
any JdkThreadLocal? Is an additional reference field in each and every
ThreadLocalMap (one per Thread that uses thread locals) a bigger price to
pay? I don't know. Will let others comment on this.

Otherwise the code looks good. Just a couple of observations:

Since private static method JdkThreadLocal.add is only called from
JdkThreadLocal constructor with just constructed instance (this), there's
no possibility for it to be called twice or more times with the same
instance. The check for duplicates could go away then, right?

You keep an array of Entry objects which are just wrappers for
JdkThreadLocal objects. Are you already planning for Entry to become a
WeakReference? Otherwise you could just keep JdkThreadLocal objects in the
array directly.

Regards, Peter

On 05/17/18 20:25, Tony Printezis wrote:

Hi all,

I have a new version of the code for your consideration:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/

I basically combined our two approaches. The usage is as Alan had proposed
it: Users have to use JdkThreadLocal (which is only available within
java.base) and override threadTerminated(). However, I keep track of
JdkThreadLocal instances globally (as I did before) and not per-thread.
This way we don’t need to add any unnecessary complexity to ThreadLocalMap.

Currently, I don’t allow entries to be purged if the JdkThreadLocal
instance becomes otherwise unreachable. I can easily add that functionality
if needed (I can use WeakReferences for that). However, for the uses we’re
considering, is it really necessary?

Thoughts?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 14, 2018 at 12:40:28 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

In my proposal, you can register the exit hook in the ThreadLocal c’tor, so
it’s almost as nice as Alan’s in that respect (and it doesn't require an
extra field per ThreadLocal plus two extra fields per JdkEntry)

Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-30 Thread Tony Printezis
Hi all,

Any more thoughts on this? (with apologies for the ping)

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 18, 2018 at 3:58:57 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Hi again,

Stylistically, I strongly prefer this version over the previous one (the
one with the doubly-linked list of JdkThreadLocal entries) you had posted.
This one is a lot cleaner.

A few suggestions:

* I’m not crazy about the fact that the users have to override
calculateInitialValue() instead of initialValue() as it will be a bit
error-prone. If they accidentally override initialValue() then the
per-thread registering is not going to happen. Maybe I’m overthinking this.
One way to get round this is for each JdkThreadLocal instance to delegate
calls to get(), set(), and remove() to a private ThreadLocal instance,
which can in turn delegate initialValue() to the outer instance. (Hope this
makes sense?) I did a quick prototype of this and it seems to work, but I
didn’t heavily test it.

* I would prefer if the method users override actually took the
thread-local value as a parameter, i.e., protected void threadTerminated(T
value). This is very easy to add:

protected void threadTerminated(T value) {
}

private void threadTerminated() {
threadTerminated(get());
}

and I think it will be easier to use, as most uses will probably need to do
get() anyway.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 18, 2018 at 4:23:19 AM, Peter Levart (peter.lev...@gmail.com) wrote:

It's good to have alternative implementations on the table. Here's another
variant that is space neutral for threads that don't use JdkThreadLocal,
but also scales to many JdkThreadLocal instances:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.02/

Now we only need an arbiter to decide which one! :-)

Regards, Peter

On 05/17/18 22:39, Peter Levart wrote:

Hi Tony,

If we anticipate only small number of JdkThreadLocal(s) (there will be only
one for the start) then this is a plausible solution. Then perhaps this
limitation should be written somewhere in the JdkThreadLocal javadoc so
that one day somebody will not be tempted to use JdkThreadLocal(s) en
masse. Let's say there will be a few more JdkThreadLocal(s) in the future.
Are we willing to pay for a few lookups into a ThreadLocalMap at each and
every thread's exit even though such thread did not register a mapping for
any JdkThreadLocal? Is an additional reference field in each and every
ThreadLocalMap (one per Thread that uses thread locals) a bigger price to
pay? I don't know. Will let others comment on this.

Otherwise the code looks good. Just a couple of observations:

Since private static method JdkThreadLocal.add is only called from
JdkThreadLocal constructor with just constructed instance (this), there's
no possibility for it to be called twice or more times with the same
instance. The check for duplicates could go away then, right?

You keep an array of Entry objects which are just wrappers for
JdkThreadLocal objects. Are you already planning for Entry to become a
WeakReference? Otherwise you could just keep JdkThreadLocal objects in the
array directly.

Regards, Peter

On 05/17/18 20:25, Tony Printezis wrote:

Hi all,

I have a new version of the code for your consideration:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/

I basically combined our two approaches. The usage is as Alan had proposed
it: Users have to use JdkThreadLocal (which is only available within
java.base) and override threadTerminated(). However, I keep track of
JdkThreadLocal instances globally (as I did before) and not per-thread.
This way we don’t need to add any unnecessary complexity to ThreadLocalMap.

Currently, I don’t allow entries to be purged if the JdkThreadLocal
instance becomes otherwise unreachable. I can easily add that functionality
if needed (I can use WeakReferences for that). However, for the uses we’re
considering, is it really necessary?

Thoughts?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 14, 2018 at 12:40:28 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

In my proposal, you can register the exit hook in the ThreadLocal c’tor, so
it’s almost as nice as Alan’s in that respect (and it doesn't require an
extra field per ThreadLocal plus two extra fields per JdkEntry). :-)

But, I do like the addition of the JdkEntry list to avoid unnecessarily
iterating over all the map entries (which was my main concern with Alan’s
original webrev). I’ll be totally happy with a version of this.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 12, 2018 at 6:44:08 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi,

On 05/11/18 16:13, Alan Bateman wrote:

On 08/05/2018 16:07, Tony Printezis wrote:

Hi all,

Following the discussion on this a few weeks ago, here’s the first version
of the change:

h

Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-18 Thread Tony Printezis
Hi again,

Stylistically, I strongly prefer this version over the previous one (the
one with the doubly-linked list of JdkThreadLocal entries) you had posted.
This one is a lot cleaner.

A few suggestions:

* I’m not crazy about the fact that the users have to override
calculateInitialValue() instead of initialValue() as it will be a bit
error-prone. If they accidentally override initialValue() then the
per-thread registering is not going to happen. Maybe I’m overthinking this.
One way to get round this is for each JdkThreadLocal instance to delegate
calls to get(), set(), and remove() to a private ThreadLocal instance,
which can in turn delegate initialValue() to the outer instance. (Hope this
makes sense?) I did a quick prototype of this and it seems to work, but I
didn’t heavily test it.

* I would prefer if the method users override actually took the
thread-local value as a parameter, i.e., protected void threadTerminated(T
value). This is very easy to add:

protected void threadTerminated(T value) {
}

private void threadTerminated() {
threadTerminated(get());
}

and I think it will be easier to use, as most uses will probably need to do
get() anyway.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 18, 2018 at 4:23:19 AM, Peter Levart (peter.lev...@gmail.com) wrote:

It's good to have alternative implementations on the table. Here's another
variant that is space neutral for threads that don't use JdkThreadLocal,
but also scales to many JdkThreadLocal instances:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.02/

Now we only need an arbiter to decide which one! :-)

Regards, Peter

On 05/17/18 22:39, Peter Levart wrote:

Hi Tony,

If we anticipate only small number of JdkThreadLocal(s) (there will be only
one for the start) then this is a plausible solution. Then perhaps this
limitation should be written somewhere in the JdkThreadLocal javadoc so
that one day somebody will not be tempted to use JdkThreadLocal(s) en
masse. Let's say there will be a few more JdkThreadLocal(s) in the future.
Are we willing to pay for a few lookups into a ThreadLocalMap at each and
every thread's exit even though such thread did not register a mapping for
any JdkThreadLocal? Is an additional reference field in each and every
ThreadLocalMap (one per Thread that uses thread locals) a bigger price to
pay? I don't know. Will let others comment on this.

Otherwise the code looks good. Just a couple of observations:

Since private static method JdkThreadLocal.add is only called from
JdkThreadLocal constructor with just constructed instance (this), there's
no possibility for it to be called twice or more times with the same
instance. The check for duplicates could go away then, right?

You keep an array of Entry objects which are just wrappers for
JdkThreadLocal objects. Are you already planning for Entry to become a
WeakReference? Otherwise you could just keep JdkThreadLocal objects in the
array directly.

Regards, Peter

On 05/17/18 20:25, Tony Printezis wrote:

Hi all,

I have a new version of the code for your consideration:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/

I basically combined our two approaches. The usage is as Alan had proposed
it: Users have to use JdkThreadLocal (which is only available within
java.base) and override threadTerminated(). However, I keep track of
JdkThreadLocal instances globally (as I did before) and not per-thread.
This way we don’t need to add any unnecessary complexity to ThreadLocalMap.

Currently, I don’t allow entries to be purged if the JdkThreadLocal
instance becomes otherwise unreachable. I can easily add that functionality
if needed (I can use WeakReferences for that). However, for the uses we’re
considering, is it really necessary?

Thoughts?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 14, 2018 at 12:40:28 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

In my proposal, you can register the exit hook in the ThreadLocal c’tor, so
it’s almost as nice as Alan’s in that respect (and it doesn't require an
extra field per ThreadLocal plus two extra fields per JdkEntry). :-)

But, I do like the addition of the JdkEntry list to avoid unnecessarily
iterating over all the map entries (which was my main concern with Alan’s
original webrev). I’ll be totally happy with a version of this.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 12, 2018 at 6:44:08 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi,

On 05/11/18 16:13, Alan Bateman wrote:

On 08/05/2018 16:07, Tony Printezis wrote:

Hi all,

Following the discussion on this a few weeks ago, here’s the first version
of the change:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/

I think the consensus was that it’d be easier if the exit hooks were only
available within java.base. Is it enough that I added the functionality to
the jdk.internal.mis

Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-18 Thread Tony Printezis
Hi Peter,

Thanks for taking a look at the new webrev!

Initially, I think we’re expecting two uses of JdkThreadLocal: one in
sun.nio.ch.Utils, shown on my webrev and my original motivation for working
on this, and one in sun.nio.fs.NativeBuffers, as shown on Alan’s webrev
(I’m not familiar with that part of the code at all; I assume it’s
addressing a similar issue to sun.nio.ch.Utils).

When I originally brought up this issue, Alan said that he's only expecting
2-3 uses (literally) inside java.base, so I did the implementation
accordingly and tried to keep it as simple as possible. We could maybe look
at other uses of ThreadLocal inside java.base to get a better sense of how
many more will benefit from a thread termination callback?

Response to your comments:

I can definitely add javadoc to explain the limitations of the
implementation. It takes me a long time to write coherent javadoc /
comments, so I wanted to make sure we have the right approach first before
I did that. :-)

Re: sanity tests in add(): I was being paranoid but, sure, I can remove
them.

Re: Entry objects: You’re absolutely right. I did it this way to make it
easier to extend WeakReference if needed. It also keeps the code a bit less
verbose. I can use JdkThreadLocal directly.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 17, 2018 at 4:39:20 PM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi Tony,

If we anticipate only small number of JdkThreadLocal(s) (there will be only
one for the start) then this is a plausible solution. Then perhaps this
limitation should be written somewhere in the JdkThreadLocal javadoc so
that one day somebody will not be tempted to use JdkThreadLocal(s) en
masse. Let's say there will be a few more JdkThreadLocal(s) in the future.
Are we willing to pay for a few lookups into a ThreadLocalMap at each and
every thread's exit even though such thread did not register a mapping for
any JdkThreadLocal? Is an additional reference field in each and every
ThreadLocalMap (one per Thread that uses thread locals) a bigger price to
pay? I don't know. Will let others comment on this.

Otherwise the code looks good. Just a couple of observations:

Since private static method JdkThreadLocal.add is only called from
JdkThreadLocal constructor with just constructed instance (this), there's
no possibility for it to be called twice or more times with the same
instance. The check for duplicates could go away then, right?

You keep an array of Entry objects which are just wrappers for
JdkThreadLocal objects. Are you already planning for Entry to become a
WeakReference? Otherwise you could just keep JdkThreadLocal objects in the
array directly.

Regards, Peter

On 05/17/18 20:25, Tony Printezis wrote:

Hi all,

I have a new version of the code for your consideration:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/

I basically combined our two approaches. The usage is as Alan had proposed
it: Users have to use JdkThreadLocal (which is only available within
java.base) and override threadTerminated(). However, I keep track of
JdkThreadLocal instances globally (as I did before) and not per-thread.
This way we don’t need to add any unnecessary complexity to ThreadLocalMap.

Currently, I don’t allow entries to be purged if the JdkThreadLocal
instance becomes otherwise unreachable. I can easily add that functionality
if needed (I can use WeakReferences for that). However, for the uses we’re
considering, is it really necessary?

Thoughts?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 14, 2018 at 12:40:28 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

In my proposal, you can register the exit hook in the ThreadLocal c’tor, so
it’s almost as nice as Alan’s in that respect (and it doesn't require an
extra field per ThreadLocal plus two extra fields per JdkEntry). :-)

But, I do like the addition of the JdkEntry list to avoid unnecessarily
iterating over all the map entries (which was my main concern with Alan’s
original webrev). I’ll be totally happy with a version of this.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 12, 2018 at 6:44:08 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi,

On 05/11/18 16:13, Alan Bateman wrote:

On 08/05/2018 16:07, Tony Printezis wrote:

Hi all,

Following the discussion on this a few weeks ago, here’s the first version
of the change:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/

I think the consensus was that it’d be easier if the exit hooks were only
available within java.base. Is it enough that I added the functionality to
the jdk.internal.misc package? (And is jdk.internal.misc the best place for
this?)

I’ll also add a test for the new functionality. But let’s first come up
with an approach that everyone is happy with. :-)

Peter's approach in early April was clean (and we should come to the
getIfPresent discussion) but it adds a field to

Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-17 Thread Tony Printezis
Hi all,

I have a new version of the code for your consideration:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.1/

I basically combined our two approaches. The usage is as Alan had proposed
it: Users have to use JdkThreadLocal (which is only available within
java.base) and override threadTerminated(). However, I keep track of
JdkThreadLocal instances globally (as I did before) and not per-thread.
This way we don’t need to add any unnecessary complexity to ThreadLocalMap.

Currently, I don’t allow entries to be purged if the JdkThreadLocal
instance becomes otherwise unreachable. I can easily add that functionality
if needed (I can use WeakReferences for that). However, for the uses we’re
considering, is it really necessary?

Thoughts?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 14, 2018 at 12:40:28 PM, Tony Printezis (tprinte...@twitter.com)
wrote:

Peter,

In my proposal, you can register the exit hook in the ThreadLocal c’tor, so
it’s almost as nice as Alan’s in that respect (and it doesn't require an
extra field per ThreadLocal plus two extra fields per JdkEntry). :-)

But, I do like the addition of the JdkEntry list to avoid unnecessarily
iterating over all the map entries (which was my main concern with Alan’s
original webrev). I’ll be totally happy with a version of this.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 12, 2018 at 6:44:08 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi,

On 05/11/18 16:13, Alan Bateman wrote:

On 08/05/2018 16:07, Tony Printezis wrote:

Hi all,

Following the discussion on this a few weeks ago, here’s the first version
of the change:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/

I think the consensus was that it’d be easier if the exit hooks were only
available within java.base. Is it enough that I added the functionality to
the jdk.internal.misc package? (And is jdk.internal.misc the best place for
this?)

I’ll also add a test for the new functionality. But let’s first come up
with an approach that everyone is happy with. :-)

Peter's approach in early April was clean (and we should come to the
getIfPresent discussion) but it adds a field to Thread for the callback
list. If I read your approach correctly, you are avoiding that by
maintaining an array of hooks in ThreadLocalExitHooks.

Another approach to try is a java.base-internal ThreadLocal that defines a
method to be invoked when a thread terminates. Something like the
following:
   http://cr.openjdk.java.net/~alanb/8202788/webrev/index.html

-Alan


>From the API perspective, Alan's suggestion is the most attractive one as
it puts the method to where it belongs - into the ThreadLocal instance. But
the implementation could be improved a bit. I don't like the necessity to
iterate over all ThreadLocal(s) to filter out JdkThreadLocal(s). There
might be a situation where there's plenty of ThreadLocal(s) registered per
exiting thread which would produce a spike in CPU processing at thread exit.

The way to avoid this would be to maintain a separate linked list of
entries that contains just those with JdkThreadLocal(s). Like in this
modification of Alan's patch, for example:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.01/

(Only ThreadLocal class is modified from Alan's patch)

What do you think?


Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-14 Thread Tony Printezis
Peter,

In my proposal, you can register the exit hook in the ThreadLocal c’tor, so
it’s almost as nice as Alan’s in that respect (and it doesn't require an
extra field per ThreadLocal plus two extra fields per JdkEntry). :-)

But, I do like the addition of the JdkEntry list to avoid unnecessarily
iterating over all the map entries (which was my main concern with Alan’s
original webrev). I’ll be totally happy with a version of this.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 12, 2018 at 6:44:08 AM, Peter Levart (peter.lev...@gmail.com) wrote:

Hi,

On 05/11/18 16:13, Alan Bateman wrote:

On 08/05/2018 16:07, Tony Printezis wrote:

Hi all,

Following the discussion on this a few weeks ago, here’s the first version
of the change:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/

I think the consensus was that it’d be easier if the exit hooks were only
available within java.base. Is it enough that I added the functionality to
the jdk.internal.misc package? (And is jdk.internal.misc the best place for
this?)

I’ll also add a test for the new functionality. But let’s first come up
with an approach that everyone is happy with. :-)

Peter's approach in early April was clean (and we should come to the
getIfPresent discussion) but it adds a field to Thread for the callback
list. If I read your approach correctly, you are avoiding that by
maintaining an array of hooks in ThreadLocalExitHooks.

Another approach to try is a java.base-internal ThreadLocal that defines a
method to be invoked when a thread terminates. Something like the
following:
   http://cr.openjdk.java.net/~alanb/8202788/webrev/index.html

-Alan


>From the API perspective, Alan's suggestion is the most attractive one as
it puts the method to where it belongs - into the ThreadLocal instance. But
the implementation could be improved a bit. I don't like the necessity to
iterate over all ThreadLocal(s) to filter out JdkThreadLocal(s). There
might be a situation where there's plenty of ThreadLocal(s) registered per
exiting thread which would produce a spike in CPU processing at thread exit.

The way to avoid this would be to maintain a separate linked list of
entries that contains just those with JdkThreadLocal(s). Like in this
modification of Alan's patch, for example:

http://cr.openjdk.java.net/~plevart/jdk-dev/DBBCache_Cleanup/webrev.01/

(Only ThreadLocal class is modified from Alan's patch)

What do you think?


Regards, Peter


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-14 Thread Tony Printezis
Alan and Peter,

First, I need to apologize: I completely missed Peter’s proposal (for some
reason Peter’s follow-up e-mails show up blank on my mail client). Could
someone point me to it so I can take a look?

Re: having info per thread vs. globally: Having a couple more objects and a
field per-thread will probably not be a huge deal, memory footprint-wise.
But, and with my GC implementer hat on :-), avoiding that and only
maintaining a single global entry per-ThreadLocal can only be a good thing,
IMHO.

Re: Alan’s approach vs. my approach: I like Alan’s approach given that it
doesn’t require any additional data structures / memory footprint to keep
track of the hooks (only an extra class). The only downside I can think of
is that it requires an iteration over all entries in each ThreadLocal map
even if there are no ThreadLocals with an exit hook. My proposal only
iterates over the exit hooks (and it’s essentially a nop if there are
none). If we assume there will be a very small number of exit hooks, and
potentially many entries in some TL maps, this will be a win and keep
Thread::exit a bit leaner.

Having said all this, I’ll be very happy to just get this fix done. So,
feel free to decide on which approach is most appropriate! :-) I’ll be
happy with any of the proposals.

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 11, 2018 at 10:13:30 AM, Alan Bateman (alan.bate...@oracle.com)
wrote:

On 08/05/2018 16:07, Tony Printezis wrote:
> Hi all,
>
> Following the discussion on this a few weeks ago, here’s the first
version
> of the change:
>
> http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/
>
> I think the consensus was that it’d be easier if the exit hooks were only
> available within java.base. Is it enough that I added the functionality
to
> the jdk.internal.misc package? (And is jdk.internal.misc the best place
for
> this?)
>
> I’ll also add a test for the new functionality. But let’s first come up
> with an approach that everyone is happy with. :-)
>
Peter's approach in early April was clean (and we should come to the
getIfPresent discussion) but it adds a field to Thread for the callback
list. If I read your approach correctly, you are avoiding that by
maintaining an array of hooks in ThreadLocalExitHooks.

Another approach to try is a java.base-internal ThreadLocal that defines
a method to be invoked when a thread terminates. Something like the
following:
   http://cr.openjdk.java.net/~alanb/8202788/webrev/index.html

-Alan


Re: RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-08 Thread Tony Printezis
David,

Please see inline.


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On May 8, 2018 at 11:44:11 AM, David Lloyd (david.ll...@redhat.com) wrote:

I'm not a reviewer, but I would ask: how sure are we that it's OK to
use lambdas from here? Is there a chance that the magic bootstrap
stuff won't yet be initialized at the time when an early thread could
exit for whatever reason?


I’m not aware that lambdas cannot be used at particular points in the JVM’s
execution. Is that really a concern? (FWIW, the code I posted compiles and
runs fine.)



Anyway I think using a lambda with forEach is probably overkill in
atThreadExit. A simple for loop would suffice IMO.


That’s not straightforward, though. Note that the iteration is done by the
ThreadLocal class, not the ThreadLocalExitHooks class. So, a for-loop won’t
work, unless I expose the array to the ThreadLocal class, which I’d rather
not do. I could use an Iterator. But using forEach() is a lot nicer (IMHO
of course).



Also, I would be quite surprised if there wasn't a way to get a system
property from system code without having to use doPrivileged; that
might bear some researching.


I just copied how the Utils class reads the jdk.nio.maxCachedBufferSize
property (see the existing getMaxCachedBufferSize() method).



Could this all be simplified to drop the necessity for passing around
the thread local map and thread local instances? The sun.nio.ch.Util
has static access to its ThreadLocal, so really all it needs is to be
able to give a Runnable to run at thread exit and it can take care of
the rest.


Not quite sure what you mean by “passing around the thread local map and
thread local instances”. The map is only passed from Thread to ThreadLocal,
so the latter can call exit hooks (if any). So, the map doesn’t escape the
Thread / ThreadLocal classes.

The thread local instance is only used to associate that instance with an
exit hook in the ThreadLocalExitHooks class.

It’d be nice if I could pass a Runnable to be called at thread exit.
However, how do I do that? Will there be a method on ThreadLocal to set
this Runnable. If that’s the case, can we arrange for a method on
ThreadLocal to only be used within java.base module (remember: we don’t
want this functionality to be used outside java.base)? Additionally, if
it’s just a Runnable, how does it get the thread’s ThreadLocal value when
it runs? If the ThreadLocal is not set for that thread, get() will create
it, which will be a waste of an allocation.


It could be a simple as keeping an ArrayList of Runnables
on Thread or in another ThreadLocal.


But this requires at least a couple of objects per Thread. What I
implemented has a single entry for each ThreadLocal, irrespective of how
many threads set it (so a lot less overhead).

Tony



On Tue, May 8, 2018 at 10:07 AM, Tony Printezis 
wrote:
> Hi all,
>
> Following the discussion on this a few weeks ago, here’s the first version

> of the change:
>
> http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/
>
> I think the consensus was that it’d be easier if the exit hooks were only
> available within java.base. Is it enough that I added the functionality to

> the jdk.internal.misc package? (And is jdk.internal.misc the best place
for
> this?)
>
> I’ll also add a test for the new functionality. But let’s first come up
> with an approach that everyone is happy with. :-)
>
> One additional question: I put the new functionality conditional on a
> property (jdk.nio.freeBuffersAtThreadExit) and it’s off by default. Should

> I make it on by default? Or just not add the property all-together?
>
> Tony
>
>
> —
> Tony Printezis | @TonyPrintezis | tprinte...@twitter.com



-- 
- DML


RFR: JDK-8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

2018-05-08 Thread Tony Printezis
Hi all,

Following the discussion on this a few weeks ago, here’s the first version
of the change:

http://cr.openjdk.java.net/~tonyp/8202788/webrev.0/

I think the consensus was that it’d be easier if the exit hooks were only
available within java.base. Is it enough that I added the functionality to
the jdk.internal.misc package? (And is jdk.internal.misc the best place for
this?)

I’ll also add a test for the new functionality. But let’s first come up
with an approach that everyone is happy with. :-)

One additional question: I put the new functionality conditional on a
property (jdk.nio.freeBuffersAtThreadExit) and it’s off by default. Should
I make it on by default? Or just not add the property all-together?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-06 Thread Tony Printezis
Hi Alan,

Ah, I hadn’t realized that there’s already some tight coupling between
Thread and nio. OK, I’ll just call into sun.nio directly and see what the
reviewers say. :-) Is there a CR for this already? Or should I create one?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On April 6, 2018 at 12:45:29 PM, Alan Bateman (alan.bate...@oracle.com)
wrote:

On 06/04/2018 15:08, Tony Printezis wrote:

Hi Alan,

Calling sun.nio directly from java.lang seemed a bit dodgy to me, which is
why I proposed some type of exit hook (maybe I overthought this?). But
that’d be OK, could make this change a lot simpler. :-) And, yes, I came
across the issue of not being able to query whether a ThreadLocal exists on
a Thread when I implemented my prototype. Which is why I think introducing
an exit hook on ThreadLocal, instead of Thread, is probably the better
approach (it will only be called if the ThreadLocal exists).

java.lang.Thread is already tightly connected to blocking I/O operations
(Thread::interrupt for example). In any case, the concern with exposing
exit hooks in the API is that it means running arbitrary code when exiting,
something that would need a lot of consideration before going there.

-Alan


Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-06 Thread Tony Printezis
—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On April 6, 2018 at 12:16:10 PM, David Lloyd (david.ll...@redhat.com) wrote:

On Fri, Apr 6, 2018 at 8:57 AM, Tony Printezis 
wrote:
>> ThreadLocal clearing
>
> Could you clarify what you mean by ThreadLocal clearing?

I mean calling ThreadLocal#remove().


I see. So, anyone who subclasses ThreadLocal can override remove(). And if
remove() is called by Thread::exit, it can be used as an exit hook. (David
Holmes, if this is what you meant in your e-mail: apologies; I
misunderstood.)



> I like the suggestion to add an overridable exit() method to ThreadLocal.
If
> you want to avoid calling user code by Thread::exit, would adding
> ThreadLocals (which are tagged appropriately) to a queue for later
> processing a better approach (similar to the mechanism used for
References /
> ReferencesQueues)? The user can of course create a memory leak by not
> polling the queue frequently enough. But, that’s also the case for
> References. And at least user code cannot block Thread::exit.

It's more complexity, and at some point you have to ask: is it better
to block thread A or thread B? At least blocking thread A is somewhat
expected.


I agree re: it’d add complexity. #simplify :-)

Tony



-- 
- DML


Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-06 Thread Tony Printezis
Was there a reason why this was not introduced in the first place?

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On April 6, 2018 at 8:49:17 AM, Peter Levart (peter.lev...@gmail.com) wrote:



On 04/06/2018 10:02 AM, Alan Bateman wrote:
> On 05/04/2018 22:45, Tony Printezis wrote:
>> Hi all,
>>
>> We recently hit another interesting issue with the NIO thread-local
>> DirectByteBuffer cache. One of our services seems to create and drop
>> threads at regular intervals. I assume this is due to a thread pool
>> dynamically resizing itself.
>>
>> Let's say a thread starts, lives long enough for its Thread object to be
>> promoted to the old gen (along with its cached direct buffer), then
>> exits.
>> This will result in its cached direct buffer(s) being unreachable in the
>> old gen and will only be reclaimed after the next full GC /
>> concurrent GC
>> cycle.
>>
> Right, if a short lived thread does I/O with a buffer backed by an
> array in the heap then any direct buffers in its thread local cache
> won't be freed until there is a GC and reference processing. It's
> something that I've prototyped a few times and always leaned towards
> not exposing anything in the API, instead just hooking into the thread
> exit to clear the buffer cache. One thing to watch out for is that the
> buffer cache may not exist (as the thread didn't do any I/O with heap
> buffers) so you'll end up creating (an empty) buffer cache at thread
> exit. That is benign of course but still unsettling to have additional
> code executing at this time.
>
> -Alan

An internal method, let's say ThreadLocal.probe(), that would return
thread-local value only if it has already been initialized, would be
helpfull. Maybe it could be exposed as new public API too. I remember
that I needed it in the past:

public T probe() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return null;
}


Regards, Peter


Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-06 Thread Tony Printezis
Hi Alan,

Calling sun.nio directly from java.lang seemed a bit dodgy to me, which is
why I proposed some type of exit hook (maybe I overthought this?). But
that’d be OK, could make this change a lot simpler. :-) And, yes, I came
across the issue of not being able to query whether a ThreadLocal exists on
a Thread when I implemented my prototype. Which is why I think introducing
an exit hook on ThreadLocal, instead of Thread, is probably the better
approach (it will only be called if the ThreadLocal exists).

Tony


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On April 6, 2018 at 4:02:56 AM, Alan Bateman (alan.bate...@oracle.com)
wrote:

On 05/04/2018 22:45, Tony Printezis wrote:
> Hi all,
>
> We recently hit another interesting issue with the NIO thread-local
> DirectByteBuffer cache. One of our services seems to create and drop
> threads at regular intervals. I assume this is due to a thread pool
> dynamically resizing itself.
>
> Let's say a thread starts, lives long enough for its Thread object to be
> promoted to the old gen (along with its cached direct buffer), then
exits.
> This will result in its cached direct buffer(s) being unreachable in the
> old gen and will only be reclaimed after the next full GC / concurrent GC
> cycle.
>
Right, if a short lived thread does I/O with a buffer backed by an array
in the heap then any direct buffers in its thread local cache won't be
freed until there is a GC and reference processing. It's something that
I've prototyped a few times and always leaned towards not exposing
anything in the API, instead just hooking into the thread exit to clear
the buffer cache. One thing to watch out for is that the buffer cache
may not exist (as the thread didn't do any I/O with heap buffers) so
you'll end up creating (an empty) buffer cache at thread exit. That is
benign of course but still unsettling to have additional code executing
at this time.

-Alan


Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-06 Thread Tony Printezis
Hi David,

Thanks for your thoughts. Please see inline.


—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On April 5, 2018 at 6:24:11 PM, David Lloyd (david.ll...@redhat.com) wrote:

On Thu, Apr 5, 2018 at 4:45 PM, Tony Printezis 
wrote:
> Would proposing to introduce thread exit hooks be reasonable? Or is
> everyone going to freak out? :-) The hooks can be either per-Thread or
even
> per-ThreadLocal. And it's OK if the hooks can only be used within
java.base.

User-accessible thread exit hooks would be nice, from a user
perspective. From a JDK perspective - it adds new opportunities for
user code to jam things up, so it's a tradeoff.


…just like finalizers. :-) Yeah, I get that. Which is why I was a bit
reluctant to bring it up. Which is why I proposed to only make it available
within java.base?



ThreadLocal clearing


Could you clarify what you mean by ThreadLocal clearing?


on thread exit would have been nice back in the
beginning, but now I think it would be a fairly substantial behavior
change. Adding a new exit() method on ThreadLocal would be better
(but not perfect) compatibility-wise, and see prior note about users
jamming things up...


I like the suggestion to add an overridable exit() method to ThreadLocal.
If you want to avoid calling user code by Thread::exit, would adding
ThreadLocals (which are tagged appropriately) to a queue for later
processing a better approach (similar to the mechanism used for References
/ ReferencesQueues)? The user can of course create a memory leak by not
polling the queue frequently enough. But, that’s also the case for
References. And at least user code cannot block Thread::exit.



I think that at a minimum, explicitly releasing thread-local NIO
direct buffers on thread exit (without introducing a user facing API)
is probably safe.


I’m also pretty sure it’s safe. I should have mentioned that the
thread-local direct buffers are actually explicitly freed when they are not
put back in the cache. So, it should be safe to also explicitly free any
that are in the cache when the thread exits.


Some kind of user-accessible hook would be nice,
but I can't imagine it would take anything less than a massive
discussion to get there.


I’d like to avoid a massive discussion, which is why I proposed to only
make it available within java.base.

Tony



-- 
- DML


Re: Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-06 Thread Tony Printezis
Hi David,

ThreadLocals getting cleared is not enough. The threadLocals field is
cleared by Thread::exit:

private void exit() {
...
threadLocals = null;
...
}

but this doesn’t really do anything. The GC has to run, find the direct
buffer in the ThreadLocal unreachable, and queue its Cleaner for
processing. I’m looking for a hook to explicitly reclaim the direct buffer
when Thread::exit is called.

Tony

—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


On April 5, 2018 at 6:07:26 PM, David Holmes (david.hol...@oracle.com)
wrote:

Hi Tony,

On 6/04/2018 7:45 AM, Tony Printezis wrote:
> Hi all,
>
> We recently hit another interesting issue with the NIO thread-local
> DirectByteBuffer cache. One of our services seems to create and drop

If it's in a ThreadLocal then aren't you just asking for thread-locals
to be cleared at thread exit?

Cheers,
David

> threads at regular intervals. I assume this is due to a thread pool
> dynamically resizing itself.
>
> Let's say a thread starts, lives long enough for its Thread object to be
> promoted to the old gen (along with its cached direct buffer), then
exits.
> This will result in its cached direct buffer(s) being unreachable in the
> old gen and will only be reclaimed after the next full GC / concurrent GC
> cycle.
>
> Interestingly, the service in question does concurrent GC cycles really
> infrequently (one every few days) as it has a really low promotion rate.
> This results in the JVM's total direct size constantly increasing (which
is
> effectively a native buffer leak).
>
> Has anyone come across this issue before?
>
> There are a few obvious ways to mitigate this, e.g., cause a Full GC /
> concurrent GC cycle at regular intervals. However, the best solution IMHO
> is to explicitly free any direct buffers that are still in the cache when
a
> thread exits.
>
> I'll be happy to implement this and test it internally at Twitter, if
it's
> not on anyone else's radar. However, to do what I'm proposing I need some
> sort of thread exit hook. Unfortunately, there doesn't seem to be one.
>
> Would proposing to introduce thread exit hooks be reasonable? Or is
> everyone going to freak out? :-) The hooks can be either per-Thread or
even
> per-ThreadLocal. And it's OK if the hooks can only be used within
java.base.
>
> FWIW, I did a simple prototype of this (I call the hooks from
Thread::exit)
> and it seems to work as expected.
>
> Any thoughts / feedback on this will be very appreciated.
>
> Thanks,
>
> Tony
>
>
>
> —
> Tony Printezis | @TonyPrintezis | tprinte...@twitter.com
>


Promptly freeing the per-thread cached direct buffers when a thread exits

2018-04-05 Thread Tony Printezis
Hi all,

We recently hit another interesting issue with the NIO thread-local
DirectByteBuffer cache. One of our services seems to create and drop
threads at regular intervals. I assume this is due to a thread pool
dynamically resizing itself.

Let's say a thread starts, lives long enough for its Thread object to be
promoted to the old gen (along with its cached direct buffer), then exits.
This will result in its cached direct buffer(s) being unreachable in the
old gen and will only be reclaimed after the next full GC / concurrent GC
cycle.

Interestingly, the service in question does concurrent GC cycles really
infrequently (one every few days) as it has a really low promotion rate.
This results in the JVM's total direct size constantly increasing (which is
effectively a native buffer leak).

Has anyone come across this issue before?

There are a few obvious ways to mitigate this, e.g., cause a Full GC /
concurrent GC cycle at regular intervals. However, the best solution IMHO
is to explicitly free any direct buffers that are still in the cache when a
thread exits.

I'll be happy to implement this and test it internally at Twitter, if it's
not on anyone else's radar. However, to do what I'm proposing I need some
sort of thread exit hook. Unfortunately, there doesn't seem to be one.

Would proposing to introduce thread exit hooks be reasonable? Or is
everyone going to freak out? :-) The hooks can be either per-Thread or even
per-ThreadLocal. And it's OK if the hooks can only be used within java.base.

FWIW, I did a simple prototype of this (I call the hooks from Thread::exit)
and it seems to work as expected.

Any thoughts / feedback on this will be very appreciated.

Thanks,

Tony



—
Tony Printezis | @TonyPrintezis | tprinte...@twitter.com


RFR: 8151098: Introduce multi-slot per-thread cache for StringDecoders/Encoders

2016-03-02 Thread Tony Printezis
Hi all,

We discussed this change in a previous e-mail thread. Here’s a patch for your 
consideration:

http://cr.openjdk.java.net/~tonyp/8151098/webrev.1/

I cloned the Cache class from ThreadLocalCoders and reworked it a bit. The 
StringDecoder and StringEncoder classes had some common fields (the Charset and 
the requested charset name). I moved them to a superclass (StringCoder) which 
made the cache easier to write (I didn’t have to create one subclass for the 
decoder and one for the encoder, as it is the case in ThreadLocalCoders).

Feedback very welcome!

Tony

-

Tony Printezis | JVM/GC Engineer / VM Team | Twitter

@TonyPrintezis
tprinte...@twitter.com



Re: Frequent allocations / promotions of StringCoding$String{Encoder,Decoder} objects

2016-02-29 Thread Tony Printezis
All,

Thanks for the replies!

Aleksey,

Thanks for pointing me to the CR (JDK-4806753). I’m a bit confused though. The 
CR was resolved as fixed but Mark’s patch doesn’t seem to have made it to the 
StringCoding.java file (I checked the JDK 8 and 9 source repos; also the class 
sources in src.zip in 1.5.0_1, the Fixed In release, and for good measure last 
5 and 6 releases). However, I noticed that the cache in 
java.nio.cs.ThreadLocalCoders looks very similar to Mark's cache. Was it 
decided to maybe cache the CharsetEncoders/Decoders instead of the 
StringCoding$StringEncoders/Decoders (i.e., was that the fix for JDK-4806753)? 
Unfortunately, this is pre-mercurial so I can’t get the history on this. Any 
volunteers at Oracle?

One more observation: the change that introduced the SoftReferences:

-    /* The cached coders for each thread
-     */
-    private static ThreadLocal decoder = new ThreadLocal();
-    private static ThreadLocal encoder = new ThreadLocal();
+    /** The cached coders for each thread */
+    private final static ThreadLocal> decoder =
+        new ThreadLocal>();
+    private final static ThreadLocal> encoder =
+        new ThreadLocal>();

was done by this changeset:

changeset:   18:b5da6145b050
user:        martin
date:        Sun Mar 09 21:56:42 2008 -0700
files:       src/share/classes/java/lang/StringCoding.java
description:
6671834: (str) Eliminate StringCoding.java compile warnings
Reviewed-by: iris

Relevant CR:

https://bugs.openjdk.java.net/browse/JDK-6671834

There is no explanation of why SoftReferences were introduced. The only comment 
from Martin is “A fine things to do.” Eliminating compilation warnings is 
indeed a fine thing to do. Piggy-backing functional changes on that without any 
explanation is not (FWIW). I personally propose to remove the use of 
SoftReferences moving forward.

Going back to introducing the caches to StringCoding: I can replicate what’s in 
java.nio.cs.ThreadLocalCoders or I can re-use the ThreadLocalCoders.Cache 
class. I’d rather do the latter. Any thoughts on what the best way to do this 
is (move it to a file by itself, make the class public, etc.)?

Tony

On February 25, 2016 at 4:16:32 PM, Aleksey Shipilev 
(aleksey.shipi...@oracle.com) wrote:

On 02/25/2016 11:48 PM, Tony Printezis wrote:  
> Has anyone identified this issue before?  

Hm, there is a blast from the past:  
https://bugs.openjdk.java.net/browse/JDK-4806753  

In comments there, Mark suggests a patch that apparently handles  
multiple coders. I wonder where did that go. Also, Martin Buchholz is  
still an assignee there :)  

> We believe that caching a small number of coders per thread (instead  
> of just one) could avoid this unnecessary churn. We’ll be happy to  
> contribute such a fix if there’s interest in getting it accepted.  

Yes, this seems important.  

Thanks,  
-Aleksey  

-

Tony Printezis | JVM/GC Engineer / VM Team | Twitter

@TonyPrintezis
tprinte...@twitter.com



Frequent allocations / promotions of StringCoding$String{Encoder,Decoder} objects

2016-02-25 Thread Tony Printezis
Hi all,

We recently noticed that in several of our production services there are very 
frequent allocations / promotions of coder objects from the StringCoding class 
(e.g. java.lang.StringCoding$String{Encoder,Decoder} instances). We are pretty 
sure that these are allocated to replace the coders cached in the StringCoding 
ThreadLocals (we also see SoftReferences being allocated / promoted along with 
the coder objects):

    /** The cached coders for each thread */
    private final static ThreadLocal> decoder =
        new ThreadLocal<>();
    private final static ThreadLocal> encoder =
        new ThreadLocal<>();

We seem to be doing encoding / decoding using at least two different charsets 
(we also see Encoder / Decoders for those two charsets being allocated / 
promoted) which is causing this churn (i.e., the coder allocations are not 
caused by the SoftReferences being cleared; they are frequently replaced when a 
coder for a different charset is required). Even though we observed this 
behavior with JDK 8 it should also exist in JDK 9 (StringCoding still has the 
same two ThreadLocals; we can confirm this very easily).

Has anyone identified this issue before? We believe that caching a small number 
of coders per thread (instead of just one) could avoid this unnecessary churn. 
We’ll be happy to contribute such a fix if there’s interest in getting it 
accepted.

Also, why are SoftReferences used here? In our case, if a thread does some 
encoding / decoding once it’s likely it will likely keep doing it for ever. So 
the use of SoftReferences here is not very helpful (it adds unnecessary 
overhead to the GC, not only due to the extra copying but also due to the extra 
work required during reference processing). Was there a specific reason for the 
use of SoftReferences here?

Finally, the StringCoding coder c'tor allocates a new Charset coder 
(Charset{Encoder,Decoder}) for the specific charset. But such Charset coders 
already seem to be cached in ThreadLocals in the sun.nio.cs.ThreadLocalCoders 
class. Any reason why we cannot re-use those? (Oh, and also note that this 
cache does not use SoftReferences, which makes their use by the StringCoding 
class even more perplexing.)

(a tip of the hat to my colleague Peter Beaman for discovering this issue)

Tony

-

Tony Printezis | JVM/GC Engineer / VM Team | Twitter

@TonyPrintezis
tprinte...@twitter.com



Re: JDK 9 RFR of JDK-8148627: Problem list TestMaxCachedBufferSize.java

2016-02-02 Thread Tony Printezis
Thanks Joe!

On January 29, 2016 at 3:13:37 PM, joe darcy (joe.da...@oracle.com) wrote:

Hi Alan, 

Limiting the test to 64-bit platforms is fine with me; I'll push the 
change as you've suggested later today. 

Thanks, 

-Joe 

On 1/29/2016 11:59 AM, Alan Bateman wrote: 
> 
> 
> On 29/01/2016 18:53, joe darcy wrote: 
>> Hello, 
>> 
>> Until JDK-8148540 is addressed, the test 
>> 
>> sun/nio/ch/TestMaxCachedBufferSize.java 
>> 
>> should be problem listed on the platforms is fails on. Please review 
>> the patch below. 
>> 
> I think this test will be tricky to be reliable on 32-bit so the 
> simplest is to just restrict it to 64-bit with: 
> 
> @requires (sun.arch.data.model == "64") 
> 
> -Alan. 
> 

-

Tony Printezis | JVM/GC Engineer / VM Team | Twitter

@TonyPrintezis
tprinte...@twitter.com