Hi Pavel,

There's a RFR being discussed on core-libs-dev: "8138696 : java.lang.ref.Cleaner - an easy to use alternative to finalization". Although it does not currently support it, I have been doing experiments with FinalReference(s) (a package-private subtype of Reference that is used internally to support finalization) that allowed me to code a simple pool of recyclable objects that works with the help of GC and reachability.

The idea is very simple:

ConcurrentLinkedDequeue<T> pool = ...;
Cleaner cleaner = ...;

T getPooledInstance(Supplier<T> factory) {
    T instance = pool.pollLast();
    if (instance == null) {
        instance = factory.get();
    }
    // register cleanup to recycle the instance
    cleaner.finalizableCleanup(instance, pool::addFirst);
}

.... finalize() method allows for cleanup to be performed at most once for each finalizable instance, but an API like Cleaner that explicitly registers a FinalReference with an instance would allow it to be recycled and re-registered multiple times.

If you are interested to explore this possibility for recycling of ByteBuffer(s), I can try proposing this to the Cleaner API.

Regards, Peter

On 10/13/2015 11:40 AM, Pavel Rappo wrote:
Hi Simone,

On 8 Oct 2015, at 20:51, Simone Bordet <simone.bor...@gmail.com> wrote:

The *API* should provide a callback to notify when the ByteBuffer has
been consumed.
Here is a proposed mechanism for managing buffers used by Listener.

1. WebSocket.Builder gets 2 new methods (may not be an actual javadoc):

     /**
      * Specifies a function that provides {@code ByteBuffer}s for {@code
      * WebSocket} to receive Binary, Ping and Pong messages' payload to.
      *
      * <p> The function is called by {@code WebSocket} with a number of
      * bytes should remain in the required buffer. This serves as a hint
      * from the implementation to a user.
      *
      * @param provider the providing function
      * @return this builder
      */
     public Builder byteBuffersForListener(IntFunction<? extends ByteBuffer> 
provider);

     /**
      * Specifies a function that provides {@code CharBuffer}s for {@code
      * WebSocket} to receive Text and Close messages' payload to.
      *
      * <p> The function is called by {@code WebSocket} with a number of
      * chars should remain in the required buffer. This serves as a hint
      * from the implementation to a user.
      *
      * @param provider the providing function
      * @return this builder
      */
     public Builder charBuffersForListener(IntFunction<? extends CharBuffer> 
provider);

2. If a user wants to use their own strategy of allocation/reuse they are fully
in charge of this. For example:

     IntFunction<? extends CharBuffer> provider = (r) -> {
         CharBuffer charBuffer = pool.getWithRemaining(r);
         if (charBuffer == null)
             charBuffer = CharBuffer.allocate(r);
         return charBuffer;
     };

     ...
     builder.charBuffersForListener(provider) ... .buildAsync();
     ...

     Later in the listener far, far away:

     @Override
     public void onText(CharBuffer payload, boolean isLast) {
         // ...
         ws.sendText(payload, isLast).thenRun(() -> pool.recycle(payload));
     }

Since the user constructs both the listener and the provider, they surely may 
now
of each other, so the 'pool' can be easily captured by the listener.

3. On the other hand we could specify a set of predefined providers, and default
behaviour like:

     * one off provider: constructs buffers on demand for one time use
     * reusing provider: always returns a buffer to the implementation at the
       end of the onXXX invocation

In both cases above the user doesn't have to know about some additional
recycle-handlers. Hence there's no need for onXXX methods to change their
signatures to accommodate for it.

What would you think about it?

-Pavel


Reply via email to