[
https://issues.apache.org/jira/browse/KUDU-3567?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
YifanZhang reassigned KUDU-3567:
--------------------------------
Assignee: YifanZhang
> 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
> Assignee: YifanZhang
> Priority: Major
>
> 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)