Problem
*Note: this issue is only reproducible in an emulator, not a device*
After a set of UI objects is created and then each one is nulled, the resources that they consume are not freed and reused. Hence, the GC process is not working correctly.
DDMS shows the memory and objects always increasing.
Note that nulling the objects inside the mainViews() scope should not be necessary. Hence, when the issue affecting the first test case below has been fixed, the second test case should be tested to confirm proper behavior.
Tested and works correclty on the following devices:
* HTC Sensation + HTC Sense 3.0 + Android 2.3.4 + Titanium 2.0.0 (2012/03/01 14:01 0ccdf63) + v8
* Droid 1 (Android 2.2) + Titanium 2.0.0 (2012/02/28) + v8
Test case
* run each of the following code, in turn
* click button to create objects
* wait for "mainViews function has stopped" before clicking button again
* repeat several times until app crashes
Test case 1
With nulling objects inside mainViews():
var app = require('testApp');
app.createUI();
var noOfViews = 50;
var mainViewsIterations = 0;
function generateViews(noOfViews) {
Ti.API.info('****** mainViews function has started ******');
var views =[];
var view = null;
for (var i=0; i < noOfViews; i++) {
view = Ti.UI.createView();
views.push(view);
}
Ti.API.info('Titanium views created and added to array');
for (var j in views){
views[j] = null;
}
Ti.API.info('Titanium views removed and nulled');
views = null;
Ti.API.info('****** mainViews function has stopped ******');
mainViewsIterations++;
return mainViewsIterations;
}
exports.createUI = function(){
var win = Ti.UI.createWindow({
backgroundColor: "white"
});
var button = Ti.UI.createButton({
title: 'create ' + noOfViews + ' views'
});
button.addEventListener("click", function(e) {
Ti.API.info('Total views created: ' + generateViews(noOfViews) * noOfViews);
});
win.add(button);
win.open();
};
Test case 2
Without nulling objects inside mainViews():
var noOfViews = 50;
var mainViewsIterations = 0;
function mainViews(noOfViews) {
Ti.API.info('****** mainViews function has started ******');
var views =[];
var view = null;
for (var i=0; i < noOfViews; i++) {
view = Ti.UI.createView();
views.push(view);
}
Ti.API.info('Titanium views created and added to array');
Ti.API.info('****** mainViews function has stopped ******');
mainViewsIterations++;
return mainViewsIterations;
}
var win = Ti.UI.createWindow({
backgroundColor: "white"
});
var button = Ti.UI.createButton({
title: 'create ' + noOfViews + ' views'
});
button.addEventListener("click", function(e) {
Ti.API.info('Total views created: ' + mainViews(noOfViews) * noOfViews);
});
win.add(button);
win.open();
Logs
Testing with:
* Titanium 2.0.0 (2012/02/21 13:31 5ff41b6)
* Android APIs 2.2
* v8
528 AndroidRuntime D >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
528 AndroidRuntime D CheckJNI is ON
528 AndroidRuntime D --- registering native functions ---
80 ActivityManager I Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.appcelerator.testing10/.Testing10Activity }
80 ActivityManager I Start proc com.appcelerator.testing10 for activity com.appcelerator.testing10/.Testing10Activity: pid=534 uid=10036 gids={1015, 3003}
528 AndroidRuntime D Shutting down VM
528 AndroidRuntime I NOTE: attach of thread 'Binder Thread #3' failed
534 TiApplication I (main) [0,0] checkpoint, app created.
534 TiApplication I (main) [540,540] Titanium 2.0.0 (2012/02/21 13:31 5ff41b6)
534 TiFastDev D (main) [143,683] Enabling Fastdev on port 42737
534 TiFastDev D (main) [13,696] sent tokens successfully
534 TiFastDev D (main) [1,697] Fastdev session handshake succesful.
534 TiApplication I (main) [12,709] Titanium Javascript runtime: v8
534 TiRootActivity I (main) [0,0] checkpoint, on root activity create, savedInstanceState: null
534 TiApplication E (KrollRuntimeThread) [1003,1003] APP PROXY: ti.modules.titanium.app.AppModule@44f695a8
534 TiAssetHelper D Fetching "app.js" with Fastdev...
534 TiRootActivity I (main) [0,0] checkpoint, on root activity resume. activity = com.appcelerator.testing10.Testing10Activity@44f00240
80 ActivityManager I Displayed activity com.appcelerator.testing10/.Testing10Activity: 3325 ms (total 3325 ms)
534 TiAPI I ****** mainViews function has started ******
534 TiAPI I Titanium views created and added to array
534 TiAPI I Titanium views removed and nulled
534 TiAPI I ****** mainViews function has stopped ******
534 TiAPI I ****** mainViews function has started ******
534 TiAPI I Titanium views created and added to array
534 TiAPI I Titanium views removed and nulled
534 TiAPI I ****** mainViews function has stopped ******
534 TiAPI I ****** mainViews function has started ******
534 TiAPI I Titanium views created and added to array
534 TiAPI I Titanium views removed and nulled
534 TiAPI I ****** mainViews function has stopped ******
534 TiAnalyticsSvc W (Thread-12) [28612,28612] Analytics Service Started
534 TiAnalyticsSvc I (Thread-12) [39,28651] Sending 1 analytics events.
534 TiAPI I ****** mainViews function has started ******
534 TiAnalyticsSvc W (Thread-12) [2103,30754] Stopping Analytics Service
534 TiAPI I Titanium views created and added to array
534 TiAPI I Titanium views removed and nulled
534 TiAPI I ****** mainViews function has stopped ******
534 TiAPI I ****** mainViews function has started ******
534 dalvikvm-heap I Clamp target GC heap from 24.151MB to 24.000MB
534 TiAPI I Titanium views created and added to array
534 TiAPI I Titanium views removed and nulled
534 TiAPI I ****** mainViews function has stopped ******
534 TiAPI I ****** mainViews function has started ******
534 dalvikvm-heap I Clamp target GC heap from 25.462MB to 24.000MB
534 dalvikvm-heap I Clamp target GC heap from 25.833MB to 24.000MB
534 dalvikvm-heap I Clamp target GC heap from 25.884MB to 24.000MB
534 dalvikvm-heap I Clamp target GC heap from 25.890MB to 24.000MB
534 dalvikvm-heap I Clamp target GC heap from 25.891MB to 24.000MB
534 dalvikvm-heap I Clamp target GC heap from 25.891MB to 24.000MB
534 dalvikvm-heap I Forcing collection of SoftReferences for 48-byte allocation
534 dalvikvm-heap I Clamp target GC heap from 25.891MB to 24.000MB
534 dalvikvm-heap E Out of memory on a 48-byte allocation.
534 dalvikvm-heap I Clamp target GC heap from 25.891MB to 24.000MB
534 dalvikvm-heap I Forcing collection of SoftReferences for 136-byte allocation
534 dalvikvm-heap I Clamp target GC heap from 25.891MB to 24.000MB
534 dalvikvm-heap E Out of memory on a 136-byte allocation.
489 DEBUG I *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
489 DEBUG I Build fingerprint: 'generic/sdk/generic/:2.2/FRF91/43546:eng/test-keys'
489 DEBUG I pid: 534, tid: 543 >>> com.appcelerator.testing10 <<<
489 DEBUG I signal 11 (SIGSEGV), fault addr deadd00d
489 DEBUG I r0 00000374 r1 0000000c r2 0000000c r3 deadd00d
489 DEBUG I r4 00000026 r5 80887fc4 r6 00000000 r7 fffe6624
489 DEBUG I r8 814a0670 r9 47ba1964 10 00265200 fp 45904e60
489 DEBUG I ip 808881ec sp 47ba1818 lr afd154c5 pc 8083b162 cpsr 20000030
489 DEBUG I #00 pc 0003b162 /system/lib/libdvm.so
489 DEBUG I #01 pc 0002cff4 /system/lib/libdvm.so
489 DEBUG I #02 pc 0002d11a /system/lib/libdvm.so
489 DEBUG I #03 pc 00035972 /system/lib/libdvm.so
489 DEBUG I #04 pc 0006a640 /data/data/com.appcelerator.testing10/lib/libkroll-v8.so
489 DEBUG I #05 pc 0006a6a4 /data/data/com.appcelerator.testing10/lib/libkroll-v8.so
489 DEBUG I #06 pc 0006a76a /data/data/com.appcelerator.testing10/lib/libkroll-v8.so
489 DEBUG I #07 pc 0006cd38 /data/data/com.appcelerator.testing10/lib/libkroll-v8.so
489 DEBUG I
489 DEBUG I code around pc:
489 DEBUG I 8083b140 1861447c 200618a2 e878f7d8 f7d82000
489 DEBUG I 8083b150 4808e9e4 6bdb5823 d0002b00 4b064798
489 DEBUG I 8083b160 701c2426 ea5cf7d8 0004ce80 fffe4ae0
489 DEBUG I 8083b170 fffe801c 00000374 deadd00d b510b40e
489 DEBUG I 8083b180 4c0a4b09 447bb083 aa05591b 6b5bca02
489 DEBUG I
489 DEBUG I code around lr:
489 DEBUG I afd154a4 b0834a0d 589c447b 26009001 686768a5
489 DEBUG I afd154b4 220ce008 2b005eab 1c28d003 47889901
489 DEBUG I afd154c4 35544306 d5f43f01 2c006824 b003d1ee
489 DEBUG I afd154d4 bdf01c30 0002ae7c 000000d4 1c0fb5f0
489 DEBUG I afd154e4 43551c3d a904b087 1c16ac01 604d9004
489 DEBUG I
489 DEBUG I stack:
489 DEBUG I 47ba17d8 00000015
489 DEBUG I 47ba17dc afd1453b /system/lib/libc.so
489 DEBUG I 47ba17e0 afd405a0 /system/lib/libc.so
489 DEBUG I 47ba17e4 afd4054c /system/lib/libc.so
489 DEBUG I 47ba17e8 00000000
489 DEBUG I 47ba17ec afd154c5 /system/lib/libc.so
489 DEBUG I 47ba17f0 00237cc0 [heap]
489 DEBUG I 47ba17f4 afd1450d /system/lib/libc.so
489 DEBUG I 47ba17f8 fffe6624
489 DEBUG I 47ba17fc 80887fc4 /system/lib/libdvm.so
489 DEBUG I 47ba1800 80887fc4 /system/lib/libdvm.so
489 DEBUG I 47ba1804 00000000
489 DEBUG I 47ba1808 fffe6624
489 DEBUG I 47ba180c afd1456b /system/lib/libc.so
489 DEBUG I 47ba1810 df002777
489 DEBUG I 47ba1814 e3a070ad
489 DEBUG I #00 47ba1818 00000001
489 DEBUG I 47ba181c 8082cff9 /system/lib/libdvm.so
489 DEBUG I #01 47ba1820 00000001
489 DEBUG I 47ba1824 8082d11f /system/lib/libdvm.so
33 Zygote D Process 534 terminated by signal (11)
80 ActivityManager I Process com.appcelerator.testing10 (pid 534) has died.
80 WindowManager I WIN DEATH: Window{451f0f80 com.appcelerator.testing10/com.appcelerator.testing10.Testing10Activity paused=false}
80 UsageStats I Unexpected resume of com.android.launcher while already resumed in com.appcelerator.testing10
80 InputManagerService W Got RemoteException sending setActive(false) notification to pid 534 uid 10036
Discussions
Q&A Post: [
http://developer.appcelerator.com/question/132357/memory-leaks-on-android-but-not-on-ios---very-simple-test-case]
Workaround
Until this issue is resolved, the recommendation is to use the Rhino Javascript runtime, which can be enabled by editing the tiapp.xml file (open using the Titanium Studio, to use its visual editor)
It seems that the garbage collector is not kicking in if we are creating a large number of views (5000 in this case) in a tight loop.
Is there any technical explanation why variables needs to (or must) be nullified? In test case above, in "mainViews" function all variables are local variables, therefore, they should be automatically GC when that function finishes with execution.
Just to add one more thing. IMHO, setting variable to "null" could have sense in cases when circular reference is present (which GC misses to detect). Something like this:
Setting "win1" to "null" after calling "close" in this case have sense. I tried to run this example and memory seems to stay constant. Am I missing something? :) Are there more memory leak patterns?
Thanks Ivan - I was just being thorough. ;) However, I have updated the ticket to clarify the observations.
We have done some testing with the latest build of titanium (2.0.0.v20120301000143) and found the same memory leak problem in rhino as well, so I don't think your workaround is valid.
Athanasios - I've deduced that this is an emulator issue, and hence works as expected on a device. Note that this is a v8 issue (see title). If you have a problem with Rhino, that you are able to prove, please raise another ticket. Thanks
As I said on Q/A topic, I can reproduce this issue on device (Thinkpad tablet, Android 3.1). It seems that adding view to a window makes the difference. Here is my test case:
If "newWin" code is commented out, memory is not freed.
Paul, I've seen the title (I am not blind...) and I know that this issue concerns V8. The reason I mentioned Rhino is your Workaround Recommendation to use the Rhino Javascript runtime! Thanks
I confirm Ivan's test case. It seems that adding view to a window makes the difference!!!
Hi Guys, I have just completed testing Ivan's code on my Android phone (2.3.4) and the emulator - the app never releases memory and I can make it crash after about 10 clicks every time. I left the newWin.Open() un-commented and click the 5k button and back button at an easy pace to give the OS time to garbage collect and it crashes. Pauls Test case: was ROOT Window and add 1000 views to it Ivan Test case: was ROOT Window with button to create 5000 views add those views to a New window and then close the window to release the memory I can confirm both test cases still crashes on emulator and phone using SDK 1.8.1 to test using V8. Ivan's test case is no different than the Memory Pool" work around that has been floating around on the Q/A blog. His test case also breaks Appceraltors own recommendation of using "Single Context" (ie single window for entire application). It also doesnt follow the rule of Nulling variables will mark it for garbage collection to eventually be released. Thank You
This may be caused by our global reference hack we use on emulator. It may have some bugs and isn't working properly. I have opened TIMOB-7706 to re-evaluate it.
Although this issue concerns V8, I can confirm that Ivan's test case crashes on emulator using both V8 and Rhino (continuous builds - version 2.0.0.v20120301000143). Mathew, could you please confirm that Ivan's code crashes on your device using Rhino as well? Thank you in advance. PS. I repeat once again that the reason I mention Rhino - although this is a V8 issue/ticket - is the Workaround Recommendation to use the Rhino Javascript runtime!
Will this also resolve memory leaks on the phone as well? Thanks
As per Paul's request. Used Test Case 1 from above. Crashes on Android Phones after 10 or so clicks. SDK: 2.0.0.v20120302121644 Studio: 1.0.8.201201262211 Android Runtime: V8 Adroid Device: HTC Verizon Thunderbolt OS Version: 2.3.4 Model: ADR6500l Android Device: HTC T-mobile G2 OS Version: 2.3.4 Model: T-Mobile G2 Is there any other information I can provide. I have testes this on 2 other devices as well. Thank You
Mathew, out of interest, are you clicking the button in quick succession, or are you waiting for the underlying code to fully complete before pressing again?
I am waiting a few seconds before each click allowing the code to complete.
Moved code for test case 1 into a commonJS module, to be certain of not polluting the global scope. However, it's not pretty - do not write commonjs modules that look like this! ;) The results in the emulator are the same as reported before.
Global scope would be polluted in case when variable is declared without "var" keyword. That is not the case here and view variables are local variables in function scope.
I have tested Seans new test case from his post and get the same results.
Hi Guys, I am getting the same results as Mathew using test case 1 from above. I have tested this on 2 Android phones running 2.3.4. The phone crashes after about 10 - 15 clicks. I also waited a little bit between each click to make sure everything was done running before clicking again. Model: HTC EVO 4g OS: 2.3.4 Model: T-Mobile G2 OS: 2.3.4 Yesterday I posted another test case because its had been mentioned in a few previous post that this is not "Real World". The test case I send yesterday should be a pretty common real world example. This sample also crashes after toggling back and forth between the 2 views. Hope this may help prove that there is an issue with memory and V8 Thank You
@Mathew, @Sean - Please confirm that you are using the 1.8.2 GA release because we had fixed a number of memory leaks in this release.
A report on my findings so far... For the two test cases in the description I am only able to produce the leak on emulator. Unable to reproduce against latest master build on Xoom (4.0.3), HTC Desire (2.2), and HTC Evo 4g (2.3.5). I believe this is related to the difference in how we manage JNI references on emulator. By disabling this different branch in the code the leak no longer occurred on the emulator. For Ivan's test case by opening a new window with a large view count. I am able to reproduce this on device and appears to be a bug related to how we clean up windows once they close. Ivan if you could file a new issue for this since it appears unrelated to the one seen on emulator for test cases 1 & 2. If anyone can still produce an out of memory crash using the two test cases in the description on device using a recent CI build (master branch) please report back with device information.
Ivan, I went ahead of filed a ticket for the bug your test case creates. Please direct your attention to TIMOB-7897. Thanks.
Hi Josh, Neeraj & Paul, As mentioned in the Problem Description: Tested and works correclty on the following devices: HTC Sensation + HTC Sense 3.0 + Android 2.3.4 + Titanium 2.0.0 (2012/03/01 14:01 0ccdf63) + v8 I am able to reproduce this issue on all of my Android Devices every single time I run both of the above test cases. This is NOT just an issue on the emulator. I believe Mathew has confirmed this earlier as well with his Android Devices. Is there a specific build that I need to use to verify your test results? It appears from the post above that you are using SDK 2.0 built on March 1st 2012. I am the March 2nd build (2.0.0.v20120302121644) with Studio build: 1.0.8.201201262211. I have just verified this again on my T-Mobile G2, HTC Thunderbolt so far and it still crashes after 10 or so clicks and waiting between each click. Mathew can you comment on the above and verify your results? Thank You
Sean, Could you verify again with a new project (just to make sure there is no stale build issues) and use the most recent CI build (March 6th, Master branch). If you can supply a log out of crash as well this may provide clues as well. Thanks for your help, hopefully we can get to the bottom of the issue.
Josh, I actually don't have memory issues with test case I provided. I suspected that window closing somehow triggers GC because in the app I'm developing, there are about 1000 components in one window (one form) and app would crash soon if memory would not be releasing.
Hi Josh, I will try that here shortly. Is there any way to create/capture the crash log on the Android device? Ivan: My and Pauls test case is not related to opening and closing windows. It is simply only to do with not releasing resources within a view when objects are set to null in that view. This is the issue that I am trying to resolve because I only open 1 root window followed by multiple views inside that window to navigate between pages/menu options. No matter what you put on the view (eg:labels, buttons, tablerows, etc) and null them - memory keeps growing and crashes the app on both the emulator and android device. I realize there is an issue with the emulator, my most pressing issue is getting this resolved on the Android device. Thanks
Hi Guys, Here is the part of log that shows Pauls test case 1 crash due to memory on my Android Phone running 2.3.4. I have the full log file, is there some place I could post the log to or email it to you guys directly if needed.
I have reproduce the same crash on multiple Android devices. Thanks for any help
Hi Guys, I have noticed that Pauls test case has changed a couple of times since this ticket was created. Just to confirm what is the code that I should be using? I see the post that Paul references test case 1 on the following: Paul Dowsett added a comment - 06/Mar/12 3:44 AM - edited Moved code for test case 1 into a commonJS module, to be certain of not polluting the global scope. However, it's not pretty - do not write commonjs modules that look like this! But as stated above you would write code like this!! This seems to be causing confusion between everyone who is trying to test this on Android device and verify the results. Can you guys confirm the code that Mathew and myself should be testing? Is someone going to change the title of the ticket back to include Android device and not just the emulator until it is proven fixed? Thank You
To stop this nullifying-paraonia :D First, you need to differentiate: value and value's reference. When doing this:
two things are done: value "1" is created and a reference is added to it, which is "a" variable. When doing this:
only one thing is done, that is, one more reference to value "1" is created. So, now there are two references to the same value. Here is the catch: by doing this:
you are not destroying value "1", you have just referenced to different value. Garbage collection counts value references, where there are no more references to some value, it can be released. So, if you do this:
you just reference other thing. Now, nothing references value "1" and therefore that memory space can be released. When it will be removed it is not up to you, but to GC mechanism. In particular case above, all view variables are local variables in function scope and they will be destroyed when function finishes with execution. References that they contain will be destroyed, nullifying them has no sense and if it is necessary, then something is terribly wrong. :) Setting variable to null could have sense in some cases, as I mentioned in one comment.
Hi Ivan, The nullifing paranoia comes from the fact that Appcelerator Recommends this as best practice in their own guides :>. Nulling something is the only way in Titanium to indicate that an object is no longer needed because there is no free method only remove method. I agree that all local variable in a function SHOULD be destroyed once the function is done executing but this is not the case. I feel like Mathews and my test cases have shown this over and over again that something is not working correctly. In none of my test cases or real world apps have I created any circular reference with objects and I have been more than careful to make sure that objects are created and destroyed in the correct order. Do you have a "Hello World" test case that will create and destroy objects that can show that there are no memory leak issues with V8 on Android device? Just to make sure this test case should not include opening and closing windows as the solution. Thank You
Yeah, they recommend that and people are paranoid and mislead because of that. Even some of their employees think that nullifying a variable destroys a value it references. Anyway, nobody knows everything (I also might have missed some technical reason they have for that, but I am pretty sure that things functions this way in other environments) and I hope explanation of variable nullifying will be more precise and comprehensive. There is my test case above and I am not experiencing memory issues on device that I use.
Ivan, Nullifying objects actually does destroy objects that they reference. My test case works perfect on iOS and if you run instruments you can see the difference between nullifying objects and not nullifying them. My sample App uses a single root window and opening views and removing them and nullifying all of the UI objects works PERFECT on iOS and not even close on Android. Thats the whole point with this ticket. Once again your above example opens another window other than your root window. And you say your self that if you remove the win.open that the objects never get destroyed. You should be able to destroy object and have them GC'd correctly just by running the function again or nullifying the variables. Openning a window should have NOTHING to do with Garbage Collection. Am I missing something with the win.open ??? Thanks
Ivan, I wrote the bit in our guides about nulling objects. And I agree, it should be a little more clear that setting a variable to null isn't a requirement for marking an object ready for GC. But for developers who aren't skilled JavaScript programmers, the recommendation can be useful. It's easy to unintentionally create a closure, leave a reference hanging in a global event listener, hoist some variable into the global namespace, etc. I'd hazard a guess that many (most?) of our developers aren't using either the require() modular pattern or the function-wrapped technique meaning they aren't getting any object reference clean up for free. Anyway, I'll make a note to revisit that guide.
@Sean - You missed to understand that part. I said that I suspected that Titanium's internal GC mechanism is triggered by window closing, or have affect on it (but in any case, window in test case should not have affect on views GC). @Tim - Yeah, I agree with you that in some cases that can be helpful. But still, precise explanation is, IMO, needed because otherwise developers are pushed into wrong direction - they will still have bad JS habits and beside that, they will wrongly think that they destroy values by setting variable to null. Setting variable to null is not solution in any case. Good JS practice might be. :) Anyway, one more thing to revise is Titanium's event system. I think it is the source of many bad habits. Something to think about in the future. ;)
Hi Tim & Ivan, I agree that creating variables inside of functions should "clean" up the reference to them when the function is done executing and without having to set them null should work. I am also wondering why the Javascript samples that Sean and I have created work correctly in iOS and the same exact code does not clean up at all in Android. Like Sean said above can either of you guys provide a sample code that does not involve opening a window as the work around for triggering garbage collection? Can someone provide sample code / test case that will work in both iOS and Android and show exactly how one should go about structuring and cleaning up views - ie using self-calling closure functions or using CommonJS module with exports that works correctly with the latest build of the SDK. I will run Ivan's test code from above again with the latest build (March 8th) and post my results. Thank you
If variables inside a function don't get released after the function scope is destroyed (assuming declared with var) -- this is a bug still.
Hi Jeff, Thanks for your feedback - appreciate your input. Can you or someone at Appcelerator please clarify with a simple example - which of the following methods you are referring to in your comment above? 1. Assigning a function to a variable and setting the variable to null? 2. Declaring local variables within a function - once the function has completed all local variables within the function will be automatically destroyed with out setting them to null? Thanks
Hi Jeff and Mathew, Here is a simple test case that works perfect with iOS and crashes due to memory on Android. The section of code that creates the labels is in a function which by definition should be released after the function is done execution. Using Instruments you can see the object count jump and then get released after a short period of time. If you run the same exact code on Android memory continues to grow until the app eventually crashes. Is there something in the code that needs to be changed to get this to work on Android device?
I have tested the code with the March 8th build and the March 2nd build and crashes on both builds. Thank You
This code has a bug You are adding an array to an array (labels). I think you meant label for the var name in the loop iOS will let you consume 100% of phones memory but android won't. iOS would eventually crash too
@Sean Creating 2000 labels in a tight loop like that will probably never give the GC a chance to kick in. As Jeff mentioned -- one fundamental difference between Android and iOS is the amount of heap space available to apps. While all these views are created, you are also blocking the JS thread. In this case, you can run into the app-specific heap limit before the GC has a chance to even run. If you try decreasing to say, 500 labels that should give the thread a chance to properly receive a GC sweep In Android, the total heap space per app depends on the hardware and OS version. Generally 16MB is the ultra-low end for older 1.x devices, 24MB and 32MB are the norm for 2.2 and 2.3 devices, and 48MB is used for Honeycomb and ICS devices (which also provide an optional AndroidManifest flag to enable up to 128MB of heap) In iOS, you are basically given free range of the total heap space available to the device. In this test case, iOS may be allowing you to allocate much more memory in the loop of 2000 labels, and once it's completed, allow a GC to properly cleanup.
Hi Jeff and Sean, I also noticed your typo with Labels and label. I corrected it and tested it on my Android device and it crashes after about 10 - 15 clicks 5 min of clicking. I can upload the trace file if necessary to help debug the issue. Jeff, I have ran Seans test case for about an half hour using Instruments and it never crashes and the transitory and live objects always grows and shrinks perfectly. Here are my results of running the app in Instruments. (I can click the buttons as fast as possible and the app never slows down) TiUILabelProxy: (Living/Transitory) Click 1 = 2000/0 View 1 displayed = 2/0 Label Overall Bytes: 3KB Click 2 = 2000/2000 View 2 displayed = 2/1 Label Overall Bytes: 3KB After 3 clicks Overall Bytes are 3.56 MB .... .... .... After 100+ clicks overall Bytes for TiUILabelProxy is 214.84 MB TiUILabelProxy Transitory object: 220,000 TiUILabelProxy Living Objects 2000 then drops to zero after 10-20 seconds of waiting. I have Seans sample app still running for over half-hour with continuous clicking trying to make it run out of memory as you suggested in iOS and can not make it crash. Thank you
@Mathew Please see my comments above about heap size limits in Android. You won't ever make it to anything like 214MB on Android because the heap limit is much lower. On most devices you will see on the order of 24, 32, or maybe 48MB total heap if you are lucky. Eventually (if you keep clicking past 100+), iOS will also run out of system heap, but it will take longer because the app's heap is shared with the rest of the system.
Hi Guys, I have been doing some testing and will post my results later today. Thank You
Tested with: * Android 2.2 APIs * v8 * ubuntu 11.10 Although Josh's fixed SDK (2.0.0 2012/03/07 13:43 1eb23a1) resolves this problem, the current master (03/19/12 16:32 6237693) does not.
Bug magnitude is higher in master. SDK: 2.0.0.v20120319003254 Android: V8 Studio: 2.0.0.201203182248 OS: Snow Leopard Devices Tested: Android Emulator 2.2, Android Emulator 2.3.3 Running code below in emulator causes crash within ten seconds. In 1.8.2, it would take a few minutes. 2.2 and 2.3.3 behavior identical. Logs attached. Not found in Android 2.2.2 Nexus One Device (tested a few minutes). Steps to Reproduce: 1. Run code.
2. Wait. Expected Result: App should not crash. Actual Result: Crash within 10 or so seconds.
[Pull Request #1774](https://github.com/appcelerator/titanium_mobile/pull/1774) sent to resolve JNI reference limit issue. Note about the test case in Dustin's comment. While this won't hit the JNI reference limit, it does use up a lot of heap. This is mainly due to the small internal between view creation loops. The previous loop may not be done before the next interval fires. This gives very little time for full GC passes. I suggest instead using a setTimeout in mainViews to schedule the next run after the loop has finished.
Josh, yeah, it probably would have been better with setTimeout, but I wanted more control over it. I always make sure view creation has completing before clicking the button again. I've tested this again, and the problem seems to be resolved in: * latest Android Tools (rev17) * Android APIs 2.2 and 2.3.3 * Titanium 2.0.0 (2012/03/19 16:33 6237693) (same as one I tested above) * v8 * ubuntu 11.10
Hi Josh - sorry about that - I didn't realise that commenting on a resolved ticket reopens it. Marking resolved again now.
Closing as Fixed. SDK: 2.0.0.v20120322091832 Android: V8 Studio: 2.0.0.201203211914 OS: Snow Leopard Devices Tested: Emulator 2.2, Emulator 2.3 Note: The app lasted for as long as it was tested (one minute).
Opening to edit label.
Re-opening to edit the label.
Labels edited