Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-5352] iOS: Turn on local caching for images

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2011-11-22T11:12:40.000+0000
Affected Version/sRelease 1.7.2
Fix Version/sSprint 2011-38, Release 1.8.0
ComponentsiOS
Labelsbranch-5062, module_imageview, qe-testadded
ReporterStephen Tramer
AssigneeStephen Tramer
Created2011-09-23T02:55:26.000+0000
Updated2011-11-22T11:12:40.000+0000

Description

Extensive stress on the system of loading local images can lead to memory warnings and jetsam purges. This is easily demonstrated by constantly setting a badge on an icon which uses a custom image (setting a badge refreshes the tab, which reloads the image). The best way to see this effect cascade is by tying available memory to the badge value via a timer, which will force repeated refreshes. SAMPLE APP ----
Titanium.UI.setBackgroundColor('#000');
var tabGroup = Titanium.UI.createTabGroup({id:'tabGroup1'});
var win1 = Titanium.UI.createWindow({backgroundColor:'white'});

var tab1 = Titanium.UI.createTab({
	icon:'bug.png',
	window:win1
});
setInterval(function() { 
	tab1.badge = parseInt(Ti.Platform.availableMemory);
}, 50);
tabGroup.addTab(tab1);
tabGroup.open();

Ideally, this will be run on device since it is more memory-constrained and jetsam will kill the app. Do NOT fix the side-effects of the caching problem (namely, that tabs are reloaded in this manner). TESTING ---- The bug is not fixed as long as the badge number on the app goes down. This app is specifically designed to not allocate additional memory beyond the occasional autoreleased value. jetsam won't necessarily terminate, and you may need to watch the app for an extended period of time (several minutes) before seeing decreases of the magnitude that will lead to the badge number fluctuating (indicating allocation/reclamation) or plummeting.

Attachments

FileDateSize
bug.png2011-09-23T02:55:26.000+00003297
localloader.js2011-09-24T05:52:48.000+00001804
remoteloader.js2011-09-24T05:50:25.000+00001418

Comments

  1. Dawson Toth 2011-09-23

    Added the branch-5062 label.
  2. Dawson Toth 2011-09-23

    I've created a very stressful app.js for you to test caching of local images. The following will download a remote image, and then progressively copy it out to disk until it reaches numberOfLocalImages (a variable at the top of the app.js). Then it will just repeatedly load those images in, for the rest of eternity. Tested with 1.8.0 master, and confirmed that memory leaks and the app will crash. In this case, it will crash very quickly. Enjoy! version=1.8.0 timestamp=09/06/11 10:54 githash=2888f72...
       var initialImage = 'http://appc.me/content/kitten.jpg';
       var numberOfLocalImages = 20;
       var fileName = 'kitten';
       var fileExtension = '.jpg';
       
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff'
       });
       
       var iterationCount = Ti.UI.createLabel({
           text: 'Iteration: Loading...', textAlign: 'center',
           bottom: 0, left: 0,
           height: 30, width: '50%',
           color: '#fff', backgroundColor: '#000'
       });
       win.add(iterationCount);
       var freeMemory = Ti.UI.createLabel({
           text: 'Free Memory: Loading...', textAlign: 'center',
           right: 0, bottom: 0,
           height: 30, width: '50%',
           color: '#fff', backgroundColor: '#000'
       });
       win.add(freeMemory);
       setInterval(function() {
           iterationCount.text = 'Iteration Count: ' + (currentImage % numberOfLocalImages) 
               + ' (Total: ' + currentImage + ')';
           freeMemory.text = 'Free Memory: ' + Ti.Platform.availableMemory;
       }, 100);
       
       var currentImage = 0;
       var imageView = Ti.UI.createImageView({
           image: initialImage,
           bottom: 30
       });
       imageView.addEventListener('load', function() {
           var file = Ti.Filesystem.getFile(
               Ti.Filesystem.applicationDataDirectory,
               fileName + (currentImage % 200) + fileExtension);
           if (!file.exists()) {
               file.write(imageView.toImage());
           }
           imageView.image = file.nativePath;
           currentImage += 1;
       });
       
       win.add(imageView);
       
       win.open();
       
  3. Dawson Toth 2011-09-23

    And here is a remote version of the above. This one seems to stabilize, so remote caching probably works (*shrug*):
       var imagePrefix = 'http://photosbydawson.com/photos/4e4f53911b9ba916d0b386c4/_MG_';
       var imageSuffix = '.480x320.jpg';
       var numberOfImages = 20;
       
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff'
       });
       
       var iterationCount = Ti.UI.createLabel({
           text: 'Iteration: Loading...', textAlign: 'center',
           bottom: 0, left: 0,
           height: 30, width: '50%',
           color: '#fff', backgroundColor: '#000'
       });
       win.add(iterationCount);
       var freeMemory = Ti.UI.createLabel({
           text: 'Free Memory: Loading...', textAlign: 'center',
           right: 0, bottom: 0,
           height: 30, width: '50%',
           color: '#fff', backgroundColor: '#000'
       });
       win.add(freeMemory);
       
       var currentImage = 0;
       var imageView = Ti.UI.createImageView({
           image: imagePrefix + currentImage + imageSuffix,
           bottom: 30
       });
       setInterval(function() {
           currentImage += 1;
           iterationCount.text = 'Iteration Count: ' + (currentImage % numberOfImages)
               + ' (Total: ' + currentImage + ')';
           freeMemory.text = 'Free Memory: ' + Ti.Platform.availableMemory;
           Ti.API.info('loading ' + imagePrefix + (currentImage % numberOfImages) + imageSuffix);
           imageView.image = imagePrefix + (currentImage % numberOfImages) + imageSuffix;
       }, 1000);
       win.add(imageView);
       
       win.open();
       
  4. Stephen Tramer 2011-09-24

    Test for remote image loading (remoteloader.js). This test passes when: - Memory stabilizes eventually - Suspending/resuming app does not disrupt the changing of the image view (and memory is stable) - After force-terminating the app (but not reinstalling), images do not download; they load from disk (rapid redisplay, low latency, etc.)
  5. Stephen Tramer 2011-09-24

    Test for local image loading (localloader.js) - more strenuous than the initial test submitted. For this test to pass: - Memory should eventually stabilize (but may be VERY LOW on device - this image is 205k!) - Forcing a memory panic should bring memory usage down significantly (on simulator); turn on DEBUG_IMAGE_CACHE and look for the "pages freed" message. Memory panics on device (if they occur) should also free up a large amount of space. Note that the initial image IS downloaded from a remote source, so have a fast connection available (otherwise the image download will time out).
  6. Reggie Seagraves 2011-09-24

    Merged in typo fix from pull request #495.
  7. Natalie Huynh 2011-11-15

    Pass: Tested with 1.8.0.1.v20111114102656 on iPad 2 4.3.5 iPhone 4s 5.0 iPod 3g 4.0.2
  8. Natalie Huynh 2011-11-22

    Open to add tag

JSON Source