Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-7779] Android: V8: Proxy memory leak on emulator.

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2012-07-04T03:38:49.000+0000
Affected Version/sRelease 1.8.0.1, Release 1.8.1
Fix Version/sRelease 2.0.0, Sprint 2012-06
ComponentsAndroid
Labelsmemory, qe-and031912, qe-testadded, regression, release-note-2.0.0
ReporterPaul Dowsett
AssigneeJosh Roesslein
Created2012-02-22T16:43:30.000+0000
Updated2012-07-05T11:29:35.000+0000

Description

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)

Attachments

FileDateSize
android 2.2 emu sdk 2.0.0.txt2012-03-19T17:06:10.000+000017896
android 2.3.3 emu sdk 2.0.0 crash.txt2012-03-19T17:06:10.000+000018143

Comments

  1. Neeraj Gupta 2012-02-22

    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.
  2. Ivan Skugor 2012-02-23

    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.
  3. Ivan Skugor 2012-02-23

    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:
       (function() {
       	
       	var win = Ti.UI.createWindow({
       		backgroundColor: '#000'
       	});
       	
       	var button = Ti.UI.createButton({
       		title: 'Create circular reference'
       	});
       	
       	button.addEventListener('click', function() {
       		
       	    var win1 = Ti.UI.createWindow({
       	    	backgroundColor: '#369'
       	    });
       	    
       		var button1 = Ti.UI.createButton({
       			title: 'Close'
       		});
       		
       		button1.addEventListener('click', function() {
       			//win1 -> button1 -> "click" event listener -> win1
       		    win1.close();
       		    Ti.API.info('Available memory: ' + Ti.Platform.availableMemory);
       		});
       		
       		win1.add(button1);
       		
       		win1.open();
       	});
       	
       	win.add(button);
       	
       	win.open();
       	
       })();
       
    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?
  4. Paul Dowsett 2012-02-23

    Thanks Ivan - I was just being thorough. ;) However, I have updated the ticket to clarify the observations.
  5. Athanasios Nikolaou 2012-03-01

    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.
  6. Paul Dowsett 2012-03-02

    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
  7. Ivan Skugor 2012-03-02

    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:
       function mainViews() {
           
           var newWin = Ti.UI.createWindow({ navBarHidden: true });
           
           Ti.API.info('****** mainViews function has started ******');
           var views =[];
           var view = null;
           for (var i=0; i < 1000; i++) {
               view = Ti.UI.createView();
               views.push(view);
               newWin.add(view);
           }
           
           
           newWin.open();
           
           
           Ti.API.info('Titanium views created and added to array');
           Ti.API.info('****** mainViews function has stopped ******');
       }
       
       var win = Ti.UI.createWindow({
           backgroundColor: "white"
       });
       
       var button = Ti.UI.createButton({
           title: "create 5k views"
       });
       button.addEventListener("click", function(e) {
           mainViews();
           Ti.API.info('Available memory: ' + Ti.Platform.availableMemory);
       });
       
       win.add(button);
       win.open();
       
    If "newWin" code is commented out, memory is not freed.
  8. Athanasios Nikolaou 2012-03-02

    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
  9. Athanasios Nikolaou 2012-03-02

    I confirm Ivan's test case. It seems that adding view to a window makes the difference!!!
  10. Mathew Rain 2012-03-02

    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
  11. Josh Roesslein 2012-03-02

    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.
  12. Athanasios Nikolaou 2012-03-02

    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!
  13. Mathew Rain 2012-03-02

    Will this also resolve memory leaks on the phone as well? Thanks
  14. Mathew Rain 2012-03-02

    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
  15. Paul Dowsett 2012-03-02

    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?
  16. Mathew Rain 2012-03-02

    I am waiting a few seconds before each click allowing the code to complete.
  17. Paul Dowsett 2012-03-06

    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.
  18. Ivan Skugor 2012-03-06

    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.
  19. Mathew Rain 2012-03-06

    I have tested Seans new test case from his post and get the same results.
  20. Sean Sean 2012-03-06

    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
  21. Neeraj Gupta 2012-03-06

    @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.
  22. Josh Roesslein 2012-03-06

    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.
  23. Josh Roesslein 2012-03-06

    Ivan, I went ahead of filed a ticket for the bug your test case creates. Please direct your attention to TIMOB-7897. Thanks.
  24. Sean Sean 2012-03-06

    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
  25. Josh Roesslein 2012-03-06

    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.
  26. Ivan Skugor 2012-03-07

    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.
  27. Sean Sean 2012-03-07

    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
  28. Sean Sean 2012-03-07

    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.
        *********************Part of Log File*****************************
        I/dalvikvm-heap(14048): Clamp target GC heap from 33.953MB to 32.000MB
        
        D/dalvikvm(14048): GC_FOR_MALLOC freed 0K, 9% free 27174K/29703K, external 3125K/4625K, paused 370ms
        
        E/dalvikvm-heap(14048): Out of memory on a 80-byte allocation.
        
        I/dalvikvm(14048): Can't dump thread 10: threadObj not set
        
        E/dalvikvm(14048): Out of memory: Heap Size=29703KB, Allocated=27174KB, Bitmap Size=3125KB, Limit=32768KB
        
        E/dalvikvm(14048): Extra info: Footprint=29703KB, Allowed Footprint=29703KB, Trimmed=592KB
        
        I/dalvikvm-heap(14048): Clamp target GC heap from 33.953MB to 32.000MB
        
        D/dalvikvm(14048): GC_FOR_MALLOC freed 0K, 9% free 27174K/29703K, external 3125K/4625K, paused 359ms
        
        I/dalvikvm-heap(14048): Forcing collection of SoftReferences for 280-byte allocation
        
        I/dalvikvm-heap(14048): Clamp target GC heap from 33.953MB to 32.000MB
        
        D/dalvikvm(14048): GC_FOR_MALLOC freed 0K, 9% free 27174K/29703K, external 3125K/4625K, paused 316ms
        
        E/dalvikvm-heap(14048): Out of memory on a 280-byte allocation.
        
        I/dalvikvm(14048): "KrollRuntimeThread" prio=5 tid=8 RUNNABLE
        
        I/dalvikvm(14048):   | group="main" sCount=0 dsCount=0 obj=0x4059f3f0 self=0x2cb898
        
        I/dalvikvm(14048):   | sysTid=14055 nice=0 sched=0/0 cgrp=default handle=2944320
        
        I/dalvikvm(14048):   | schedstat=( 42817810102 13039886438 37121 )
        
        I/dalvikvm(14048):   at java.lang.Class.newInstanceImpl(Native Method)
        
        I/dalvikvm(14048):   at java.lang.Class.newInstance(Class.java:1409)
        
        I/dalvikvm(14048):   at org.appcelerator.kroll.KrollProxy.createProxy(KrollProxy.java:116)
        
        I/dalvikvm(14048):   at org.appcelerator.kroll.runtime.v8.V8Object.nativeFireEvent(Native Method)
        
        I/dalvikvm(14048):   at org.appcelerator.kroll.runtime.v8.V8Object.fireEvent(V8Object.java:47)
        
        I/dalvikvm(14048):   at org.appcelerator.kroll.KrollProxy.doFireEvent(KrollProxy.java:441)
        
        I/dalvikvm(14048):   at org.appcelerator.kroll.KrollProxy.handleMessage(KrollProxy.java:602)
        
        I/dalvikvm(14048):   at org.appcelerator.titanium.proxy.TiViewProxy.handleMessage(TiViewProxy.java:347)
        
        I/dalvikvm(14048):   at android.os.Handler.dispatchMessage(Handler.java:95)
        
        I/dalvikvm(14048):   at android.os.Looper.loop(Looper.java:130)
        
        I/dalvikvm(14048):   at org.appcelerator.kroll.KrollRuntime$KrollRuntimeThread.run(KrollRuntime.java:102)
        
        I/dalvikvm(14048): 
        
        E/dalvikvm(14048): Out of memory: Heap Size=29703KB, Allocated=27174KB, Bitmap Size=3125KB, Limit=32768KB
        
        E/dalvikvm(14048): Extra info: Footprint=29703KB, Allowed Footprint=29703KB, Trimmed=592KB
        
        I/dalvikvm-heap(14048): Clamp target GC heap from 33.953MB to 32.000MB
        
        D/dalvikvm(14048): GC_FOR_MALLOC freed 0K, 9% free 27174K/29703K, external 3125K/4625K, paused 316ms
        
        I/dalvikvm-heap(14048): Forcing collection of SoftReferences for 280-byte allocation
        
        I/Kineto::main( 1400): WCMGetLinkMetricsCbk iRSSI:-54
        
        E/KINETO  ( 1400): KLOG004- IPA_LinkMetric: -54 -53 0 18 0 0x00
        
        E/KINETO  ( 1400): KLOG0B4- IPA_ZoneMetric: 8 8 -53 -75 -85 1 0x001 0 0
        
        I/dalvikvm-heap(14048): Clamp target GC heap from 33.953MB to 32.000MB
        
        D/dalvikvm(14048): GC_FOR_MALLOC freed 0K, 9% free 27174K/29703K, external 3125K/4625K, paused 363ms
        
        E/dalvikvm-heap(14048): Out of memory on a 280-byte allocation.
        
        I/dalvikvm(14048): "main" prio=5 tid=1 RUNNABLE
        
        I/dalvikvm(14048):   | group="main" sCount=0 dsCount=0 obj=0x40027198 self=0xce60
        
        I/dalvikvm(14048):   | sysTid=14048 nice=0 sched=0/0 cgrp=default handle=-1345006528
        
        I/dalvikvm(14048):   | schedstat=( 9586303718 1874511713 2793 )
        
        I/dalvikvm(14048):   at android.view.MotionEvent.obtain(MotionEvent.java:~383)
        
        I/dalvikvm(14048):   at android.os.MessageQueue.nativePollOnce(Native Method)
        
        I/dalvikvm(14048):   at android.os.MessageQueue.next(MessageQueue.java:119)
        
        I/dalvikvm(14048):   at android.os.Looper.loop(Looper.java:117)
        
        I/dalvikvm(14048):   at android.app.ActivityThread.main(ActivityThread.java:3683)
        
        I/dalvikvm(14048):   at java.lang.reflect.Method.invokeNative(Native Method)
        
        I/dalvikvm(14048):   at java.lang.reflect.Method.invoke(Method.java:507)
        
        I/dalvikvm(14048):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
        
        I/dalvikvm(14048):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
        
        I/dalvikvm(14048):   at dalvik.system.NativeStart.main(Native Method)
        
        I/dalvikvm(14048): 
        
        E/dalvikvm(14048): Out of memory: Heap Size=29703KB, Allocated=27174KB, Bitmap Size=3125KB, Limit=32768KB
        
        E/dalvikvm(14048): Extra info: Footprint=29703KB, Allowed Footprint=29703KB, Trimmed=592KB
        
        I/Process ( 1296): Sending signal. PID: 14048 SIG: 9
        
        W/ActivityManager( 1296):   Force finishing activity com.appdesigngeeks.paulDTest/.PauldtestActivity
        
        ***************************************************
        
    I have reproduce the same crash on multiple Android devices. Thanks for any help
  29. Sean Sean 2012-03-07

    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
  30. Ivan Skugor 2012-03-08

    To stop this nullifying-paraonia :D First, you need to differentiate: value and value's reference. When doing this:
        var a = 1;
        
    two things are done: value "1" is created and a reference is added to it, which is "a" variable. When doing this:
        var b = a;
        
    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:
        a = null;
        
    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:
        b = null;
        
    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.
  31. Sean Sean 2012-03-08

    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
  32. Ivan Skugor 2012-03-08

    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.
  33. Sean Sean 2012-03-08

    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
  34. Tim Poulsen 2012-03-08

    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.
  35. Ivan Skugor 2012-03-08

    @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. ;)
  36. Mathew Rain 2012-03-08

    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
  37. Jeff Haynie 2012-03-08

    If variables inside a function don't get released after the function scope is destroyed (assuming declared with var) -- this is a bug still.
  38. Mathew Rain 2012-03-08

    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
  39. Sean Sean 2012-03-08

    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?
        var win = Ti.UI.createWindow({
            backgroundColor: "white"
        });
        //create View 1 - yellow background
        var button = Ti.UI.createButton({
            title: "Go To View 1"
        });
        button.addEventListener("click", function(e) {
            view1New();
        }); 
        //add button to window
        win.add(button);
        //open Main window
        win.open();
         
        function view1New(){
         
            //create view 1
            var view1 = Ti.UI.createView({
                backgroundColor: 'yellow',
            });
         
            //function to create labels on each of the 2 views
            var mainLabelsFunction1 = function mainLabels() {
                Ti.API.info('****** mainLabels function has started ******');
                var labels =[];
                var label = null;
                for (var i=0; i < 2000; i++) {
                    label = Ti.UI.createLabel();
                    labels.push(labels);
                }
                Ti.API.info('Titanium labels created and added to array');
                Ti.API.info('****** mainLabels function has stopped ******');
                
            }
            //create Labels
            mainLabelsFunction1();
            mainLabelsFunction1 = null;
            
         
         
            var buttonView1 = Ti.UI.createButton({
                title: "Go To View 2"
            });
            buttonView1.addEventListener("click", function(e) {
                view2New(); 
                Ti.API.info('****** Clean Up of View 1 ******');    
                //clean up View 1
                
                     
                view1.remove(buttonView1);
                buttonView1 = null;
                win.remove(view1);
                view1 = null;
            }); 
            view1.add(buttonView1);
            win.add(view1);
        }
         
        function view2New(){
            //create view 2
            var view2 = Ti.UI.createView({
            backgroundColor: 'red',
            });
         
            //function to create labels on each of the 2 views
            var mainLabelsFunction2 = function mainLabels() {
                Ti.API.info('****** mainLabels function has started ******');
                var labels =[];
                var label = null;
                for (var i=0; i < 2000; i++) {
                    label = Ti.UI.createLabel();
                    labels.push(labels);
                }
                Ti.API.info('Titanium labels created and added to array');
                Ti.API.info('****** mainLabels function has stopped ******');
            }   
            //create Labels
            mainLabelsFunction2();
            mainLabelsFunction2 = null;
            
            
            var buttonView2 = Ti.UI.createButton({
                title: "Go To View 1"
            });
            buttonView2.addEventListener("click", function(e) { 
                view1New();
                Ti.API.info('****** Clean Up of View 2 ******');    
        
                //clean up View 1              
                view2.remove(buttonView2);
                buttonView2 = null;
                win.remove(view2);
                view2 = null;   
            }); 
         
            view2.add(buttonView2);
            //add view to main win
            win.add(view2); 
        }
        
        
    I have tested the code with the March 8th build and the March 2nd build and crashes on both builds. Thank You
  40. Jeff Haynie 2012-03-08

    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
  41. Marshall Culpepper 2012-03-08

    @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.
  42. Mathew Rain 2012-03-08

    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
  43. Marshall Culpepper 2012-03-08

    @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.
  44. Sean Sean 2012-03-12

    Hi Guys, I have been doing some testing and will post my results later today. Thank You
  45. Paul Dowsett 2012-03-19

    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.
  46. Dustin Hyde 2012-03-19

    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.
        var noOfViews = 500;
        var mainViewsIterations = 0;
        var interval = 3000;
        
        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: 'Interval: ' + interval + ', Views: ' + noOfViews
        });
        
        button.addEventListener("click", function(e) {
        	var total = mainViews(noOfViews) * noOfViews;
        	Ti.API.info('Total views created: ' + total);
        	button.title = 'Total Views Created: ' + total;
        });
        
        setInterval(function(){
        	button.fireEvent('click');
        }, interval);
        
        win.add(button);
        win.open();
        
    2. Wait. Expected Result: App should not crash. Actual Result: Crash within 10 or so seconds.
  47. Josh Roesslein 2012-03-20

    [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.
  48. Paul Dowsett 2012-03-22

    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
  49. Paul Dowsett 2012-03-22

    Hi Josh - sorry about that - I didn't realise that commenting on a resolved ticket reopens it. Marking resolved again now.
  50. Dustin Hyde 2012-03-22

    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).
  51. Dustin Hyde 2012-03-30

    Opening to edit label.
  52. Shyam Bhadauria 2012-07-04

    Re-opening to edit the label.
  53. Shyam Bhadauria 2012-07-04

    Labels edited

JSON Source