Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-11671] Use static class instead of inner class to avoid memory leak #4862

Closed

Conversation

salachi
Copy link
Contributor

@salachi salachi commented Oct 27, 2013

Change the inner classes to static classes so that parent is garbage collected even though inner class instance is referenced (in this case, the ClientRunnable and the thread)

https://jira.appcelerator.org/browse/TIMOB-11671

} finally {
if (tiClient != null)
{
tiClient.client.setRedirectHandler(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this pull request to my version of the Titanium framework and sometimes got an NPE at this line while testing. Didn't analyze this too deeply but changed the code to

DefaultHttpClient httpClient = tiClient.client;
if (httpClient != null) {
    httpClient.setRedirectHandler(null);
}               

which seems to help. The NPE did not occur anymore after this.

@salachi
Copy link
Contributor Author

salachi commented Oct 30, 2013

If abort is called, client could be null, fixed the issue. Thanks to Philet.


public ClientRunnable(int totalLength)
public ClientRunnable(int totalLength, TiHTTPClient client)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a static nested class. It is associated with an instance of TiHTTPClient and has direct access to that instance's methods and fields. So you don't need to pass the instance to the constructor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind.

@ghost ghost assigned pingwang2011 Nov 19, 2013
@pingwang2011
Copy link
Contributor

FR failed. Ran the test case but it can not run. The log is:

I/TiAPI ( 3296): START TIME: Tue Dec 03 2013 00:27:54 GMT+0000 (GMT)
D/TiProperties( 3296): (KrollRuntimeThread) [2483,2608] getInt called with key:ti.android.httpclient.maxbuffersize, def:524288
D/TiHttpClient( 3296): (KrollRuntimeThread) [1,2609] open request method=POST url=http://meijiservice.cloudapp.net/Service.asmx
D/TiHttpClient( 3296): (KrollRuntimeThread) [3,2612] Instantiating host with hostString='meijiservice.cloudapp.net', port='-1', scheme='http'
D/TiHttpClient( 3296): (KrollRuntimeThread) [2,2614] Setting ready state to 1
D/TiHttpClient( 3296): (KrollRuntimeThread) [3,2617] Instantiating http request with method='POST' and this url:
D/TiHttpClient( 3296): (KrollRuntimeThread) [1,2618] http://meijiservice.cloudapp.net/Service.asmx
D/TiHttpClient( 3296): (KrollRuntimeThread) [2,2620] Leaving send()
D/TiHttpClient( 3296): (TiHttpClient-7) [18,2638] send()
D/TiProperties( 3296): (TiHttpClient-7) [1,2639] getString called with key:ti.deploytype, def:development
D/TiHttpClient( 3296): (TiHttpClient-7) [1,2640] Preparing to execute request
D/TiHttpClient( 3296): (TiHttpClient-7) [4,2644] clearing the expired and idle connections
E/TiHttpClient( 3296): (TiHttpClient-7) [0,2644] HTTP Error (org.apache.http.conn.HttpHostConnectException): Connection to http://meijiservice.cloudapp.net refused
E/TiHttpClient( 3296): org.apache.http.conn.HttpHostConnectException: Connection to http://meijiservice.cloudapp.net refused
E/TiHttpClient( 3296): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:183)
E/TiHttpClient( 3296): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
E/TiHttpClient( 3296): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
E/TiHttpClient( 3296): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
E/TiHttpClient( 3296): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
E/TiHttpClient( 3296): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:653)
E/TiHttpClient( 3296): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
E/TiHttpClient( 3296): at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1271)
E/TiHttpClient( 3296): at java.lang.Thread.run(Thread.java:856)
E/TiHttpClient( 3296): Caused by: java.net.ConnectException: failed to connect to localhost/127.0.0.1 (port 80): connect failed: ECONNREFUSED (Connection refused)
E/TiHttpClient( 3296): at libcore.io.IoBridge.connect(IoBridge.java:114)
E/TiHttpClient( 3296): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
E/TiHttpClient( 3296): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
E/TiHttpClient( 3296): at java.net.Socket.connect(Socket.java:842)
E/TiHttpClient( 3296): at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
E/TiHttpClient( 3296): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144)
E/TiHttpClient( 3296): ... 8 more
E/TiHttpClient( 3296): Caused by: libcore.io.ErrnoException: connect failed: ECONNREFUSED (Connection refused)
E/TiHttpClient( 3296): at libcore.io.Posix.connect(Native Method)
E/TiHttpClient( 3296): at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:85)
E/TiHttpClient( 3296): at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
E/TiHttpClient( 3296): at libcore.io.IoBridge.connect(IoBridge.java:112)
E/TiHttpClient( 3296): ... 13 more
E/V8Exception( 3296): Exception occurred at app.js:79: Uncaught TypeError: Cannot call method 'getElementsByTagName' of undefined

@salachi
Copy link
Contributor Author

salachi commented Dec 3, 2013

Looks like the server http://meijiservice.cloudapp.net is no longer up

@pingwang2011
Copy link
Contributor

Need a valid test case for FR.

@ingo ingo assigned hieupham007 and unassigned pingwang2011 Feb 28, 2014
@salachi
Copy link
Contributor Author

salachi commented Mar 5, 2014

New test case is uploaded

@negupta
Copy link
Contributor

negupta commented Apr 17, 2014

@hieupham007 Can you please take a look at this PR since Ping is out?

@hieupham007
Copy link
Contributor

Spoke with Vishal on this and we don't think using static class is going to prevent any memory leak problems. Will discuss with Sunil next week.

@vishalduggal
Copy link
Contributor

First I do not think the heap usage as shown in the ticket has anything to do with the HTTPClient. It is more due to the XML DOM creation. There is no memory leak as far as I can see.

Second I do not see how using static classes helps reduce memory usage. The Java GC is smart enough to resolve circular references and will collect the handler, request, response and thread when the HTTPClient is ready for Garbage Collection. If the idea is to explicitly remove references to these instance variables in the client then they should just be nulled out at the end of the run command in the finally block of the clientRunnable.

See PR #5670

@salachi
Copy link
Contributor Author

salachi commented May 12, 2014

When I did the memory profiling using HPROF, I saw the httpclient being accumulated and the one that was holding was the inner classes. After the changing to static, I didn't see the httpclient in the heap.
Here are some of the links that I referred during the investigation
http://stackoverflow.com/questions/10864853/when-exactly-is-it-leak-safe-to-use-anonymous-inner-classes
http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

@vishalduggal
Copy link
Contributor

I understand the reasoning behind using static inner classes but the problem would arise only if the lifetime of the objects was different. I believe that the real reason the inner classes stayed around was due to the static variables validatingClient and nonValidatingClient which would keep the redirectHandler around and hence the TiHttpClient class. Can you check PR #5670 to see if the problem is resolved.

@salachi
Copy link
Contributor Author

salachi commented Jun 26, 2014

I tested with #5670 and it seems to be working

@skypanther
Copy link
Contributor

Closing this PR as the issue has been resolved via #5670 and #5794

@ingo ingo closed this Feb 6, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants