In case an image source has been changed in several times there is java.lang.OutOfMemoryError exception.
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 8032012 byte allocation with 1496439 free bytes and 1461KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:634)
at org.nativescript.widgets.Async$Http$RequestResult.readResponseStream(Async.java:350)
at org.nativescript.widgets.Async$Http$HttpRequestTask.doInBackground(Async.java:428)
at org.nativescript.widgets.Async$Http$HttpRequestTask.doInBackground(Async.java:378)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 3 more
here is the code witch I used
import {Component} from "@angular/core";
@Component({
selector: "my-app",
template: `
<StackLayout>
<Image src="{{src}}" stretch="fill" (tap)="change()"></Image>
</StackLayout>
`
})
export class AppComponent {
src;
constructor() {
this.change();
}
change() {
this.src = 'https://placekitten.com/1000/200' + parseInt('' + Math.random() * 9);
}
}
tns --version: 2.1.0
tns-core-modules: 2.2.0
tns-android 2.1.1
Hello @jakethashi,
The OutOfMemory exception is caused by working with big images.
The thing is that Android can not handle big images well, so the developers should handle the way they are passing images to Android apps using caching techniques and cropping to lower the size. There are several plugins that are handling this issue (e.g. nativescript-image-cache-it and nativescript-fresco) and also you can check the multiple threads where this behaviour is discussed, like this one
Also. you can check image-cache module (for NativeScript core only)
p.s. I also noticed that you are using the latest modules with the previous version of our CLI - you can update your NativeScript to 2.2.0 (not related to your issue - you still have to handle the way you are managing your images)
Got the same memory problem. Even worse after upgrade to 2.2.
A very traditional case that has main List page and navigate to Details page. I wrote a function to dump the memory usage for navigating from List page to Details page.
My details.xml contains below element. Note: my pic.jpg is just 500KB but watch out my measuremnt of how much memory usage difference.
<StackLayout class="header-container" row="0" backgroundImage="~/res/pic.jpg">
Here is my measurement:
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ Component โ Current version โ Latest version โ Information โ
โ nativescript โ 2.1.1 โ 2.2.0 โ Update available โ
โ tns-core-modules โ 2.1.0 โ 2.2.0 โ Update available โ
โ tns-android โ 2.1.1 โ 2.2.0 โ Update available โ
โ tns-ios โ โ 2.2.0 โ Not installed โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโ
With backgroundImage (each navigation takes +10MB increased just with 500KB jpg)
App Started:
JS: MemoryUsage=(Free=57KB; Total=3MB; Used=3MB; MaxHeap=64MB)
Navigate to details and go back and repeat it.
JS: MemoryUsage=(Free=1MB; Total=32MB; Used=31MB; MaxHeap=64MB)
JS: MemoryUsage=(Free=422KB; Total=44MB; Used=44MB; MaxHeap=64MB)
JS: MemoryUsage=(Free=2MB; Total=57MB; Used=56MB; MaxHeap=64MB)
Error: java.lang.OutOfMemoryError
Without backgroundImage (each navigation just 1MB increased)
App Started:
JS: MemoryUsage=(Free=889KB; Total=20MB; Used=19MB; MaxHeap=64MB)
Navigate to details and go back and repeat it.
JS: MemoryUsage=(Free=113KB; Total=21MB; Used=21MB; MaxHeap=64MB)
JS: MemoryUsage=(Free=58KB; Total=22MB; Used=22MB; MaxHeap=64MB)
JS: MemoryUsage=(Free=57KB; Total=24MB; Used=24MB; MaxHeap=64MB)
Error: java.lang.OutOfMemoryError
After upgrade to {N} 2.2.0
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ Component โ Current version โ Latest version โ Information โ
โ nativescript โ 2.2.0 โ 2.2.0 โ Up to date โ
โ tns-core-modules โ 2.2.0 โ 2.2.0 โ Up to date โ
โ tns-android โ 2.2.0 โ 2.2.0 โ Up to date โ
โ tns-ios โ โ 2.2.0 โ Not installed โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
With backgroundImage (first navigation already 42MB and crashed just goback)
App Started:
JS: MemoryUsage=(Free=58KB; Total=3MB; Used=3MB; MaxHeap=64MB)
Navigate to details and go back and repeat it.
JS: MemoryUsage=(Free=1MB; Total=44MB; Used=42MB; MaxHeap=64MB)
Error setting property: backgroundImage view: Error: java.lang.OutOfMemoryError
Without backgroundImage (each navigation takes +10MB increased on v2.2.0 )
App Started:
JS: MemoryUsage=(Free=57KB; Total=3MB; Used=3MB; MaxHeap=64MB)
Navigate to details and go back and repeat it.
JS: MemoryUsage=(Free=941KB; Total=32MB; Used=31MB; MaxHeap=64MB)
JS: MemoryUsage=(Free=56KB; Total=44MB; Used=44MB; MaxHeap=64MB)
JS: MemoryUsage=(Free=640KB; Total=57MB; Used=56MB; MaxHeap=64MB)
Error: java.lang.OutOfMemoryError
Any one has suggestion how to do deep memory profile in {N} to indicate the memory allocation of each object. I am still trying to find out why memory just keep up but not free up while navigating back and forth
@NickIliev, will try your suggestion and reduce the image size as well but just don't understand why +10MB overhead by including or excluding 500KB image.
Also, by looking at my comparison. The memory footprint on v2.2.0 is significant increased.
Hello @NickIliev
I used that extra large images just to show how simulate that issue quickly. In case of smaller images e.g. 100x200 you will experience that issue after some time. You may notice memory consumption will increase after playing with app and never rise down. I would like to create photo library and I don't have all images in load time. I would like to try to recycle image before its bound to view but I didn't find any API in angular. Do you have any clue. Thanks.
Hey @hshristov @slavchev can you comment here?
I have tried to switch two images in loop and after 2 minutes the app has crashed. I would say that those images aren't so big right?
import {Component} from "@angular/core";
@Component({
selector: "my-app",
template: `
<StackLayout>
<Image #image src="{{src}}" stretch="fill"></Image>
</StackLayout>
`
})
export class AppComponent {
src;
index = 0;
constructor() {
let loop = () => {
this.src = '~/img/' + ((this.index++) == 0 ? '300x500.jpeg' : '300x501.jpeg');
if (this.index > 1) {
this.index = 0;
}
setTimeout(loop, 200);
}
loop();
}
}
@jakethashi , @ryc16 thanks for your logs, code, and metrics - we need some more time to investigate further and will get back to you.
@NickIliev. Thanks.
Got another question. Currently, page.backgroundImage takes only url string. If there are different page with same backgroundImage url, would {N} handle to load only once? I guess not.
Is it possible for backgroundImage to take imageSource so that we could pass one imageSource?
Is there any workaround solution for now? Please advice!
@ryc16 please open new issue for additional questions in order to keep this one clean and focused on the current problem.
Meanwhile, you can check this solution for setting an image as a background for your page - where for background-image you can set data-URI and pass base64String. The style property background-image support url, data-URI and local resource
I have confirmed this is definitely a memory leak. It is a huge problem for anyone using NativeScript on Android to display images. No matter how small the images the app will eventually run out of memory since the bitmaps are never garbage collected, even after the component containing the image is destroyed. (By navigating away via router.)
I am connecting to a remote camera, downloading images to the documents folder and displaying them on screen. The images are quite large (6000x3000 px). Initially the second image loaded would crash the app. I followed the instructions in https://github.com/NativeScript/android-runtime/issues/77 to generate smaller thumbnails which I save to the disk. Now the fourth or fifth image crashes the app with an out of memory error.
Every time a new image is loaded I open a dialog with an Image container and set the "src" to the latest thumbnail.
Somehow NativeScript is holding onto hard references for each image loaded and they are not getting garbage collected. Apparently this is a significant problem for Android developers and the most common advise is to use weak references.
More information in this Stack Overflow question.
Here's a suggestion from the Stack Overflow question I referenced above.
public _setNativeImage(nativeImage: any) {
var weakImageRef = new WeakRef(nativeImage);
this.android.setImageBitmap(weakImageRef.get());
}
This should allow the bitmap to be garbage collected when the image component no longer references it. I'll test it out if I get some time.
Feedback from those more experienced than I?
Hey all,
We have identified and fixed leak with page transitions. It is in the master branch. We were leaking native transition object which was holding reference widgets and that was causing Java memory to increase and eventually throws OOM.
The other issue is that we have to improve the synchronisation between both garbage collectors. We will try to do it for 2.3.0 which is planned for this month.
In the mean time please check with master branch if you still see the native leak (e.g. not changing Image source in a loop but when navigating between pages) and ping me back.
@hshristov thanks for the update!
In my case I have been using the ModalDialogService
to display a full-screen preview of a captured image. After several times of opening and dismissing the dialog (different image each time) I get an OOM error. Will that be handled by the transition fix?
What are the instructions to install tns-core-modules
from master?
I created a repo with a failing loop test for this issue. (And a fix to make the test pass.)
https://github.com/colinskow/tns-image-test
On my Galaxy S7 it crashes around count 43. Simply uncomment // this.recycleImage()
to make the test pass. The ui/image
component is not allowing the image to be garbage collected after the source has changed.
If the image source is loaded from a file, resource, or URL then the native bitmap should be recycled as soon as the source is changed again or the component is unloaded. If the user passed in a NativeImage from somewhere else (cache etc.), it should be left alone in case that NativeImage is intended for later use.
Here is the relevant code:
import {Component, OnInit, ViewChild, ElementRef} from "@angular/core";
import {Page} from "ui/page";
import {Image} from "ui/image";
@Component({
selector: "my-app",
template: `
<DockLayout>
<Label [text]="msg || counter" color="white" backgroundColor="black"
textAlignment="center" width="100%" height="64" fontSize="48" dock="bottom"></Label>
<Image #image src="{{src}}" stretch="aspectFill" dock="top"></Image>
</DockLayout>
`
})
export class AppComponent implements OnInit {
src;
counter: number = 0;
msg: string = '';
index = 0;
constructor(private page: Page) {}
ngOnInit() {
this.page.actionBarHidden = true;
this.testLoop();
}
testLoop() {
let loop = () => {
// Uncomment this next line to make the test pass
// this.recycleImage();
this.src = '~/img/' + ((this.index++) == 0 ? 'image01.jpg' : 'image02.jpg');
if (this.index > 1) {
this.index = 0;
}
this.counter++;
if(this.counter < 500) {
setTimeout(loop, 100);
} else {
this.msg = "TEST PASSED!"
}
console.log(this.counter);
}
loop();
}
recycleImage() {
// Release the bitmap from memory so it can be garbage collected
// From: http://stackoverflow.com/questions/10200256/out-of-memory-error-imageview-issue
let image: Image = this.imageElem.nativeElement;
if(image && image.android) {
let drawable = image.android.getDrawable();
if(drawable) {
drawable.getBitmap().recycle();
}
}
}
@ViewChild("image") imageElem: ElementRef;
}
UPDATE: In addition to the loop test, I added a route flipping test also which swaps between pages with images. They both fail on master and 2.2.1 .
Check out the repo here:
https://github.com/colinskow/tns-image-test
I prepared a pull request on ui/image
that makes them both pass. I want to do further testing to ensure it doesn't have any unwanted side effects before submitting.
While profiling another app we found two memory leaks that are fixed in master branch and will go live with 2.3.0. They were causing native widgets to stay forever in memory which leads to OOM.
So in 2.3.0 OOM should be fixed (at most).
Now if you try to set src in a setInterval function you will still see OOM. Calling recycle
on the Bitmap solve this problem but there is no way to know when ImageSource can be safely recycled. For example using image-cache module results in exception that bitmap is recycled.
ImageView current implementation uses image-source module to load images. This means that native bitmap can be collected only after JavaScript imageSource instance is collected. This is not exactly memory leak but more garbage synchronisation issue.
With fixes in 2.3.0 if you perform navigation you probably won't see OOM Exception, we run JavaScript garbage collector when Java thread is idle.. With the next release (probably 2.3.1) we are going to change the ImageView implementation so it won't use image-source module but loads bitmaps directly in Java. This will allow Java garbage collector to release bitmaps once they are not used by ImageView widget.
I hope that this clarifies the problem.
@colinskow The transition issue was causing all native views from current page to stay alive when you navigate forward or backward. So it will definitely help but I'm not sure it will be enough. I'm in the process of completing Image refactoring so once it is in the master branch OOM should be past :).
As for using the master - the easiest way will be to install tns-core-modules@next.
Hey @colinskow,
Do you still have the same issues?
Having the same issues on NS 2.3.0 with both runtimes and tns core modules updated.
We have changed how we load images for android. Could you please get the @next version of tns-core-modules
and tns-core-modules-widgets
and try again?
I took this version 2.4.0-2016-10-11-6770 of tns and the app still crashing after a while.
JS: EXCEPTION: Error in ./AppComponent class AppComponent - inline template:2:26
JS: ORIGINAL EXCEPTION: Error: java.lang.OutOfMemoryError: Failed to allocate a 601212 byte allocation with 441144 free bytes and 430KB until OOM
JS: dalvik.system.VMRuntime.newNonMovableArray(Native Method)
JS: android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
JS: android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:752)
JS: android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:728)
JS: android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:477)
JS: com.tns.Runtime.callJSMethodNative(Native Method)
JS: com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:861)
JS: com.tns.Runtime.callJSMethodImpl(Runtime.java:726)
JS: com.tns.Runtime.callJSMethod(Runtime.java:712)
JS: com.tns.Runtime.callJSMethod(Runtime.java:693)
JS: com.tns.Runtime.callJSMethod(Runtime.java:683)
JS: com.tns.gen.java.lang.Runnable.run(Runnable.java:10)
JS: android.os.Handler.handleCallback(Handler.java:739)
JS: android.os.Handler.dispatchMessage(Handler.java:95)
JS: android.os.Looper.loop(Looper.java:145)
JS: android.app.ActivityThread.main(ActivityThread.java:5942)
JS: java.lang.reflect.Method.invoke(Native Method)
JS: java.lang.reflect.Method.invoke(Method.java:372)
JS: com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
JS: com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
JS: ORIGINAL STACKTRACE:
JS: Error: java.lang.OutOfMemoryError: Failed to allocate a 601212 byte allocation with 441144 free bytes and 430KB until OOM
JS: dalvik.system.VMRuntime.newNonMovableArray(Native Method)
JS: android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
JS: android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:752)
JS: android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:728)
JS: android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:477)
JS: com.tns.Runtime.callJSMethodNative(Native Method)
JS: com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:861)
JS: com.tns.Runtime.callJSMethodImpl(Runtime.java:726)
JS: com.tns.Runtime.callJSMethod(Runtime.java:712)
JS: com.tns.Runtime.callJSMethod(Runtime.java:693)
JS: com.tns.Runtime.callJSMethod(Runtime.java:683)
JS: com.tns.gen.java.lang.Runnable.run(Runnable.java:10)
JS: android.os.Handler.handleCallback(Handler.java:739)
JS: android.os.Handler.dispatchMessage(Handler.java:95)
JS: android.os.Looper.loop(Looper.java:145)
JS: android.app.ActivityThread.main(ActivityThread.java:5942)
JS: java.lang.reflect.Method.invoke(Native Method)
JS: java.lang.reflect.Method.invoke(Method.java:372)
JS: com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
JS: com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
JS: at Error (native)
JS: at ImageSource.loadFromFile (/data/data/org.nativescript.myappname/files/app/tns_modules/image-source/image-source.js:52:55)
JS: at Image._createImageSourceFromSrc (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/image/image-common.js:119:32)
JS: at onSrcPropertyChanged (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/image/image-common.js:20:11)
JS: at Image.DependencyObservable._onPropertyChanged (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/core/dependency-observable.js:211:13)
JS: at Image.Bindable._onPropertyChanged (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/core/bindable.js:73:45)
JS: at Image.ProxyObject._onPropertyChanged (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/core/proxy.js:45:45)
JS: at Image.View._onPropertyChanged (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/core/view-common.js:641:45)
JS: at Image.DependencyObservable._setValueInternal (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/core/dependency-observable.js:305:18)
JS: at Image.DependencyObservable._setValue (/data/data/org.nativescript.myappname/files/app/tns_modules/ui/core/dependency-observable.js:138:14)
JS: at Image.Object.defineProperty.set as src
JS: ERROR CONTEXT:
JS: [object Object]
W/System.err(22029): com.tns.Runtime.callJSMethodNative(Native Method)
W/System.err(22029): com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:861)
W/System.err(22029): com.tns.Runtime.callJSMethodImpl(Runtime.java:726)
W/System.err(22029): com.tns.Runtime.callJSMethod(Runtime.java:712)
W/System.err(22029): com.tns.Runtime.callJSMethod(Runtime.java:693)
W/System.err(22029): com.tns.Runtime.callJSMethod(Runtime.java:683)
W/System.err(22029): com.tns.Runtime.callJSMethodNative(Native Method)
W/System.err(22029): com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:861)
W/System.err(22029): com.tns.Runtime.callJSMethodImpl(Runtime.java:726)
W/System.err(22029): com.tns.Runtime.callJSMethod(Runtime.java:712)
W/System.err(22029): com.tns.Runtime.callJSMethod(Runtime.java:693)
W/System.err(22029): com.tns.Runtime.callJSMethod(Runtime.java:683)
W/System.err(22029): at com.tns.Runtime.callJSMethodNative(Native Method)
W/System.err(22029): at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:861)
W/System.err(22029): at com.tns.Runtime.callJSMethodImpl(Runtime.java:726)
W/System.err(22029): at com.tns.Runtime.callJSMethod(Runtime.java:712)
W/System.err(22029): at com.tns.Runtime.callJSMethod(Runtime.java:693)
W/System.err(22029): at com.tns.Runtime.callJSMethod(Runtime.java:683)
Hey @jakethashi,
could you please make sure to install widgets@next
as well:
tns plugin add tns-core-modules-widgets@next
tns plugin add tns-core-modules@next
Notice : Using transitions between screens leads to the exact same bug.
This is a huge issue for us right now. I can barely load 5 images into a newsfeed without it crashing.
Using "ui/image-cache" and tns-core-modules@next + tns-core-modules-widgets@next
Hey @markharding,
Can you send us your project to check locally what's going on?
Still doing some debugging, but https://github.com/Minds/mobile/blob/master/app/src/modules/newsfeed/activity/activity.component.html#L53 is an example. The images take a while to show and then after about 10 are loaded it crashes.
Avatars don't seem to be a problem at all, it's just the large full width images. Perhaps it's because the dimensions are too big?
Hey @markharding
I have cloned your app and tried to test the master branch on my side.
However, when navigating to _/tab/newsfeed_ by default only a tab is rendered with a blank page and no images or content is loaded at all.
As i didn't had user/pass I have changed so the default route will navigate using
this.routerExtensions.navigate(['/tab/newsfeed'], { clearHistory: true });
Still, no images are loading in your newsfeed section. Can you please share with us some additional information on how to retrieve your list of images/news!? (how to access activity.component.html and load some feed in it)
Also, I've noticed some points you should consider.
You have introduced custom garbage collector with the directive image-garbage-collect _ have you tested your application without the recycler for bitmaps?
@NickIliev without authentication I don't think any data will be returned. I can send you test creds privately if you want? The image-garbage-collect isn't actually doing anything / being triggered as nothing is being destroyed.
@markharding I've sent mail
Hey @markharding I have noticed that you are using image-cache in your application.
Now this module was introduced in NativeScript core but is obsolete in NativeScript + Angular-2.
With our latest release (2.4.0) the images in NativeScript are optimized and you should use it without image-cache.
Furthermore, if you still want some advanced caching techniques you can use nativescript-fresco instead and not image-cache.
IHere you can see POC NativeScript core application which in some situations is loading in list-view more than 400+ images and it works smoothly without crashes with both nativescript-fresco or
Basically, you should get rid of image-cache in angular app and use
If you choose to use nativescript-fresco with Angular-2 note that you need these additional steps.
Thanks @NickIliev. I had to implement image-cache because, without, images would pop in and out and take a while to upload.. sometimes not even display.
Also checked out fresco but has issues still with iOS.
Ah, fixed dimensions on
No need of fresco for iOS as there are rarely memory issues when working with images in iOS (this problem is mainly noticed in Android). So if using fresco you can create *ngIf to distinguish if the app is running under iOS or Android (example)
I have just created a POC app to demonstrate a list-view that loads multiple large images in list-view (N + Angular-2) - here is the direct link.
I see the same problem when setting backgroundImage property on Buttons - after displaying couple of dozens such images (not at the same time) I always get:
Binding: Binding error while setting property backgroundImage of Button(1420)[...];: Error: java.lang.OutOfMemoryError
This is still quite a problem. I get OOM from either of these:
imageSource
object from local file: var full_image = imageSource.fromFile(file_uri);
Image
view from local file: <Image src="{{ file_uri }}"></Image>
background-image
css property with local file: background-image: url('{{ file_uri }}');
For first case, I have tried to loose the references, but to no avail:
full_image.android.recycle();
full_image = null;
gc();
For the other cases - I tried removing the element manually (*ngIf) and navigating to a different component and coming back - the memory has not deallocated.
Cannot rely on fresco, because it only semi-fixes 2nd and 3rd case. Meaning - when I remove the the fresco element with *ngIf, the memory frees up. However, when using a local file, a horrendous amount of memory is being allocated from imageSource
, <Image>
, background-image
and even fresco object. a small image takes 10-20 MB of heap ... like ... wut? After displaying 5-10 images I get OOM no matter what the procedure I take.
@dxshindeo I have this app with many many images, well, I have tested like with 40 hehe. anyway, using fresco and using URL I do not get any OOM error. Each image is of course small, it is a thumbnail.... maybe your thumbnail are not small enough?
using URL
Try local file (local file not a Resource file). And is your app made in Angular2 or plain javascript? Mine is in Angular2.
The images themselves are big (1-2MB), but in fresco I show the element as:
<FrescoDrawee width="100" height="100" imageUri="{{ item.fileUri }}" actualImageScaleType="focusCrop"></FrescoDrawee>
Which should show much smaller image weight in the view. I doubt it is cramming all 1800x3600 image data in those 100x100 bounds. At least it shouldn't.
We use local resource and if image not present anymore then Amazon CloudFront, and plain JS.
I am curious if this is an open issue or if it has been fixed? I am still seeing oom issues with android / nativescript 2.5.4 and loading images into a listview. I implemented a thumbnail so the images are just a few kilobytes no more than 6 load at a time. The list view refreshes based on a drag events or zoom feature of a map so the list view reloads rather quickly.
We have tried resolving this with the FrescoDrawee library and that doesn't seem to help.
@randy-johnson When using src
property in android we internally load the bitmap in Java so bitmap memory management should not be an issue anymore. This is from 2.5.0 i think.
If you use ImageSource
instance and set it to imageSource
property of ImageView
or if you give base64 encoded string we will load the bitmap in JavaScript which may cause OOM because of the both garbage collectors synchronization. As an additional feature we support decodeWidth
, decodeHeight
and loadMode=async
properties. The first two will downsample your image so it will take less memory. The third one will load the image asynchronously meaning UI won't be blocked while image is loaded and decoded.
So my recommendation is to use ImageView
component by setting src
property. If you know the images are big then set decodeWidth and decodeHeight
. And set loadMode=async
so that loading won't block the UI thread.
ImageView will use internal memory and disk cache so image that are loaded are stored in memory cache and if they are not needed anymore they are saved in disk cache so next time you need the same image we will load it from memory or disk cache.
One additional note - if the src
starts with http
we will load it asynchronously no matter what value you have set to loadMode
.
Property useCache=false
could be used to bypass image cache and load the image as as it is first request to these url.
@hshristov , Thank you. Can you elaborate on how to use ImageView?
Are you referring to the example mentioned here?
https://docs.nativescript.org/cookbook/ui/image
or something different?
oops that google icon was the code example on the doc site lol
@hshristov So is there still a benefit of using nativescript-fresco
instead of the built-in Image view (when it comes to memory consumption and leaks)?
@randy-johnson Just set the mentioned properties on ImageView
.
@ludwiktrammer Fresco has its own features like: support for gif, webp formats but the main benefit of fresco is that it keeps the decoded bitmaps in native heap instead of Java heap. This means that your app have more available memory (there is a limit on the java memory heap) to use.
It is a matter of preference. If your app is image intensive (like gallery) I would recommend fresco, otherwise ImageView should do the work. The disadvantage of fresco is its size.
@hshristov For the past two days I've been trying to make use decodeWidth
and decodeHeight
and while there is a visible effect, it doesn't seem to work as expected (or maybe I don't understand how is this supposed to work?).
I set decodeWidth
to the width of image element in pixels (i.e. to the width in DIPs * platform.screen.mainScreen.scale) and decodeHeight
to the height of image element in pixels (i.e. to the height in DIPs * platform.screen.mainScreen.scale). I quickly noticed that after I've done this that on some devices the images started to look quite blurry. I've set stretch="none"
to see the real size of decoded images. For some reason they are too small - much smaller that what I've set in decodeHeight
and decodeWidth
. Also, the smaller the device (or maybe the smaller platform.screen.mainScreen.scale?) the worse it gets. On a Nexus 10 emulator (scale=2) they are just a little bit too small. On a 10'' Samsung tablet (scale=1.5) they are about 2 times to small. On a 7'' tablet they are about 3 times to small. I have hard time understanding what's going on.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
I am curious if this is an open issue or if it has been fixed? I am still seeing oom issues with android / nativescript 2.5.4 and loading images into a listview. I implemented a thumbnail so the images are just a few kilobytes no more than 6 load at a time. The list view refreshes based on a drag events or zoom feature of a map so the list view reloads rather quickly.
We have tried resolving this with the FrescoDrawee library and that doesn't seem to help.