dev@grizzly.java.net

Re: WorkerThread caches not clearing correctly?

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Fri, 26 Jun 2009 17:42:24 -0400

Salut,

Vivek Pandey wrote:
> Jeanfrancois Arcand wrote:
>> Salut,
>>
>> Vivek Pandey wrote:
>>> Jeanfrancois Arcand wrote:
>>>> Salut,
>>>>
>>>> Jacob Kessler wrote:
>>>>> Jeanfrancois Arcand wrote:
>>>>>>>
>>>>>>> The issue is that until that worker thread serves a new request,
>>>>>>> the context of the request holds a copy of the
>>>>>>> com.sun.grizzly.jrubyRackGrizzlyAdapter that served the request,
>>>>>>> which in turn needs to be holding objects that prevent the JRuby
>>>>>>> classloader from being garbage collected after the application
>>>>>>> that it was serving is undeployed, which means that in
>>>>>>> development environments (where requests served to redeployments
>>>>>>> approach 1:1) permgen usage climbs unreasonably. What I'm
>>>>>>> wondering is whether the Request should be cleared on application
>>>>>>> undeploy, and (if it shouldn't, for whatever reason) if there is
>>>>>>> a way to force it to clear to prevent the inappropriate caching
>>>>>>> that we are seeing.
>>>>>>
>>>>>> Hum...The Adapter is stateless by default, only one instance gets
>>>>>> created. We can probably (for JRuby) switch to a new Thread Pool
>>>>>> that clean the HttpWorkerThread's adpater instance....but since
>>>>>> this is a single instance, I don't think that will fix the issue.
>>>>>> What you need is to create a new Adapter per request...but that
>>>>>> will kill performance IMO.
>>>>>>
>>>>>> Why not clearing the JRubyAdapter state inside its service method?
>>>>>>
>>>>>> A+
>>>>>>
>>>>>> -- Jeanfrancois
>>>>>
>>>>> There is only one Adapter (which is good), and the state that it
>>>>> holds onto is an instance of the JRuby interpreter (which otherwise
>>>>> takes 5+ seconds to load). We want that JRuby interpreter to
>>>>> persist across all requests served by the adapter (as it does), but
>>>>> want to be able to clear the worker thread caches on application
>>>>> undeploy (when the Adapter is no longer in use) to free up the
>>>>> memory (particularly permgen) that the JRuby interpreter uses.
>>>>
>>>> OK, but this is not a Grizzly issue :-). Grizzly cannot by default
>>>> get rid of Adapter for trivial performance reason (sync on
>>>> ProcessorTask instance). The solution for you is to extend the
>>>> HttpWorkerThread and clear its field (In you case the ProcessorTask)
>>>> when you detect and undeploy. So you need to write your own
>>>> ThreadPool which extend the one under the http module. I can help
>>>> Thursday (holiday here now).
>>> Maybe it is not a core Grizzly issue but it is an issue with the
>>> Grizzly support in Glassfish v3.
>>>
>>> When an application is deployed, the JRuby deployer calls
>>>
>>> requestDispatcher.registerEndpoint(ctx, adapter, this);
>>>
>>> Above, *adapter* is the GrizzlyAdapter.
>>>
>>> When the application is un-deployed, the container is unregistered:
>>>
>>> requestDispatcher.unregisterEndpoint(container.getContextRoot(),
>>> container);
>>>
>>> The above unregister should have taken care of clearing off the
>>> worker thread off this JRubyGrizzlyAdapter. I think bug is right
>>> there, even after we unregister, the adapter still hangs around for
>>> no reason.
>>
>> The GrizzlyAdapter has a method call destroy(). I would think the
>> JRubyGrizzlyAdapter should clean up it's resource from there,
> We are already cleaning up the resources on undeploy. But the fact that
> JRubyGrizzlyAdapter still has references to these resources so till
> JRubyGrizzlyAdapter is unreferenced we cant get everything gced overtime.

Just curious, event if you nullify all the reference it is still causing
a leak? I'm asking because the solution is far from trivial to implement
  for v3.


>> so the instance is not causing a leak. That way we will be able to
>> re-use that instance
>
> instance of JRubyGrizzlyAdapter? We don't want that. JRubyGrizzlyAdapter
> is per application. It's lifecycle should end with the application. It
> is not shared across other apps.
>> for the next request instead of freeing the WorkerThread. If you still
>> think the WorkerThread needs to be free (we only have 5 threads per
>> default), why not clearing it inside the destroy()?
>>
>> https://grizzly.dev.java.net/nonav/apidocs/com/sun/grizzly/tcp/http11/GrizzlyAdapter.html#destroy()
>>
>>
>> Would that work?
>>
> When/who calls GrizzlyAdapter.destroy()? I see it is implemented in
> GrizzlyAdapterChain():
>
> public void destroy() {
> for (Entry<GrizzlyAdapter, String[]> adapter :
> adapters.entrySet()) {
> adapter.getKey().destroy();
> }
> }

Right but that class is not used in v3. The burden of the work will need
to happens inside the ContainerMapper class.

>
> How do I know which WorkerThread has reference to JRubyGrizzlyAdapter
> and how do I get the current WorkerThread, so that I could call
> WorkerThread.reset()?

There is no such thing implemented right now in v3 (and Grizzly). So
what needs to be done is:

(1) Store all references of created WorkerThread.
(2) As soon as you undeploy your application, cycle over all the
WorkerThread, detect if the Adapter is the one undeployed, then free it.

Note that Adapter are set on the fly, so we gonna need some synchro to
make sure we aren't freeing a Thread and at the same time the
ContainerMapper is about to set it. So this is clearly a
costly/dangerous solution IMO. But if that's the only one :-)

A+

-- Jeanfrancois


>
> -vivek.
>
>
>> A+
>>
>> -- Jeanfrancois
>>
>>
>>
>>>
>>> -vivek.
>>>
>>>
>>>>
>>>> A+
>>>>
>>>> -- Jeanfrancois
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net For
>>> additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>