Alexey Serbin created KUDU-3567:
-----------------------------------

             Summary: Resource leakage related to HashedWheelTimer in 
AsyncKuduScanner
                 Key: KUDU-3567
                 URL: https://issues.apache.org/jira/browse/KUDU-3567
             Project: Kudu
          Issue Type: Bug
          Components: client, java
    Affects Versions: 1.18.0
            Reporter: Alexey Serbin


With KUDU-3498 implemented in 
[8683b8bdb|https://github.com/apache/kudu/commit/8683b8bdb675db96aac52d75a31d00232f7b9fb8],
 now there are resource leak reports, see below.

Overall, the way how {{HashedWheelTimer}} is used for keeping scanners alive is 
in direct contradiction with the recommendation at [this documentation 
page|https://netty.io/4.1/api/io/netty/util/HashedWheelTimer.html]:
{quote}*Do not create many instances.*

HashedWheelTimer creates a new thread whenever it is instantiated and started. 
Therefore, you should make sure to create only one instance and share it across 
your application. One of the common mistakes, that makes your application 
unresponsive, is to create a new instance for every connection.
{quote}

Probably, a better way of implementing the keep-alive feature for scanner 
objects in Kudu Java client would be reusing the {{HashedWheelTimer}} instance 
from corresponding {{AsyncKuduClient}} client instance, not creating a new 
instance of the timer (along with corresponding thread) per AsyncKuduScanner 
object.  At least, an instance of {{HashedWheelTimer}} should be properly 
released/shutdown to avoid resource leakages (a running thread?) when GC-ing 
{{AsyncKuduScanner}} objects.

For example, below is an example how the leak is reported when running 
{{TestKuduClient.testStrings}}:

{noformat}
23:04:57.774 [ERROR - main] (ResourceLeakDetector.java:327) LEAK: 
HashedWheelTimer.release() was not called before it's garbage-collected. See 
https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
  io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:312)
  io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:251)
  io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:224)
  io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:203)
  io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:185)
  org.apache.kudu.client.AsyncKuduScanner.<init>(AsyncKuduScanner.java:296)
  org.apache.kudu.client.AsyncKuduScanner.<init>(AsyncKuduScanner.java:431)
  
org.apache.kudu.client.KuduScanner$KuduScannerBuilder.build(KuduScanner.java:260)
  org.apache.kudu.client.TestKuduClient.testStrings(TestKuduClient.java:692)
  sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  java.lang.reflect.Method.invoke(Method.java:498)
  
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
  
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
  
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  
org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:299)
 
org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:293)
  java.util.concurrent.FutureTask.run(FutureTask.java:266)
  java.lang.Thread.run(Thread.java:748)
{noformat}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to