Android Resources GC Issue
I am using
Drawable drawable = res.getDrawable(id);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
drawable.setBounds(0,0, width, height);
drawable.draw(canvas);
return load(bitmap, linear);
to load a drawable from a resource id into OpenGL with a given width, and height. (Using
android.opengl.GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
)
The load function does the GL-calls, and calls also bitmap.recycle().
I specify width and height myself, because Android would match the resolution to the screen size, which I don't want.
Now my problem (this part is all working fine):
if I start my app for the first time, from Android Studio, everything works; HOWEVER if I want to restart it, it crashes because of OutOfMemoryError. I am doing the exactly same calls in both cases.
I located the issue to be in the resource management of Android, as you can see in the heap analysis:
my most expensive allocations
My images are way smaller than 9 MB each in raw (512x512, RGBA, so 1 MB).
How can I prevent Android from storing these large byte arrays, which probably are meant as some kind of cache; which however doesn't run on first start after app installation?
I am testing on Android 6.0.1, API Version 23, Galaxy S5.
android bitmap opengl-es resources ram
add a comment |
I am using
Drawable drawable = res.getDrawable(id);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
drawable.setBounds(0,0, width, height);
drawable.draw(canvas);
return load(bitmap, linear);
to load a drawable from a resource id into OpenGL with a given width, and height. (Using
android.opengl.GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
)
The load function does the GL-calls, and calls also bitmap.recycle().
I specify width and height myself, because Android would match the resolution to the screen size, which I don't want.
Now my problem (this part is all working fine):
if I start my app for the first time, from Android Studio, everything works; HOWEVER if I want to restart it, it crashes because of OutOfMemoryError. I am doing the exactly same calls in both cases.
I located the issue to be in the resource management of Android, as you can see in the heap analysis:
my most expensive allocations
My images are way smaller than 9 MB each in raw (512x512, RGBA, so 1 MB).
How can I prevent Android from storing these large byte arrays, which probably are meant as some kind of cache; which however doesn't run on first start after app installation?
I am testing on Android 6.0.1, API Version 23, Galaxy S5.
android bitmap opengl-es resources ram
where do you use this?
– petey
Nov 19 '18 at 18:03
add a comment |
I am using
Drawable drawable = res.getDrawable(id);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
drawable.setBounds(0,0, width, height);
drawable.draw(canvas);
return load(bitmap, linear);
to load a drawable from a resource id into OpenGL with a given width, and height. (Using
android.opengl.GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
)
The load function does the GL-calls, and calls also bitmap.recycle().
I specify width and height myself, because Android would match the resolution to the screen size, which I don't want.
Now my problem (this part is all working fine):
if I start my app for the first time, from Android Studio, everything works; HOWEVER if I want to restart it, it crashes because of OutOfMemoryError. I am doing the exactly same calls in both cases.
I located the issue to be in the resource management of Android, as you can see in the heap analysis:
my most expensive allocations
My images are way smaller than 9 MB each in raw (512x512, RGBA, so 1 MB).
How can I prevent Android from storing these large byte arrays, which probably are meant as some kind of cache; which however doesn't run on first start after app installation?
I am testing on Android 6.0.1, API Version 23, Galaxy S5.
android bitmap opengl-es resources ram
I am using
Drawable drawable = res.getDrawable(id);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
drawable.setBounds(0,0, width, height);
drawable.draw(canvas);
return load(bitmap, linear);
to load a drawable from a resource id into OpenGL with a given width, and height. (Using
android.opengl.GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
)
The load function does the GL-calls, and calls also bitmap.recycle().
I specify width and height myself, because Android would match the resolution to the screen size, which I don't want.
Now my problem (this part is all working fine):
if I start my app for the first time, from Android Studio, everything works; HOWEVER if I want to restart it, it crashes because of OutOfMemoryError. I am doing the exactly same calls in both cases.
I located the issue to be in the resource management of Android, as you can see in the heap analysis:
my most expensive allocations
My images are way smaller than 9 MB each in raw (512x512, RGBA, so 1 MB).
How can I prevent Android from storing these large byte arrays, which probably are meant as some kind of cache; which however doesn't run on first start after app installation?
I am testing on Android 6.0.1, API Version 23, Galaxy S5.
android bitmap opengl-es resources ram
android bitmap opengl-es resources ram
edited Nov 19 '18 at 18:50
Nicol Bolas
287k33478649
287k33478649
asked Nov 19 '18 at 17:37
Antonio NoackAntonio Noack
111
111
where do you use this?
– petey
Nov 19 '18 at 18:03
add a comment |
where do you use this?
– petey
Nov 19 '18 at 18:03
where do you use this?
– petey
Nov 19 '18 at 18:03
where do you use this?
– petey
Nov 19 '18 at 18:03
add a comment |
2 Answers
2
active
oldest
votes
Implementation of texImage2D looks like this:
public static void texImage2D(int target, int level, int internalformat,
Bitmap bitmap, int border) {
if (bitmap == null) {
throw new NullPointerException("texImage2D can't be used with a null Bitmap");
}
if (bitmap.isRecycled()) {
throw new IllegalArgumentException("bitmap is recycled");
}
if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
throw new IllegalArgumentException("invalid Bitmap format");
}
}
It doesn't look like it's recycling anything. Are you sure you are not loading a huge bitmap into memory? Two calls of those are more than enough to guarantee a huge explosion in your app, if not just one (I've seen it happen many times in my app). Remember, restarting your activity does not mean restarting your proccess.
Run the Android Profiler before the first load and check how much memory it takes.
Also, you can cache and reuse bitmaps yourself.
add a comment |
I solved it (myself) by putting the files into the raw folder of the resource directory, and loading them using
fun loadBitmap(res: Resources, rawId: Int): Bitmap {
val inputStream = BufferedInputStream(res.openRawResource(rawId))
return BitmapFactory.decodeStream(inputStream)
}
and then calling
load(bitmap, linear);
and
bitmap.recycle()
like before.
Luckily those all were png/jpeg files, so I didn't need the additional features of the drawables folder. Using this, they'll automatically use their right resolution.
My Java RAM allocation is now back on 25 MB to 35 MB instead of the 110 MB when using the old way :).
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53379963%2fandroid-resources-gc-issue%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Implementation of texImage2D looks like this:
public static void texImage2D(int target, int level, int internalformat,
Bitmap bitmap, int border) {
if (bitmap == null) {
throw new NullPointerException("texImage2D can't be used with a null Bitmap");
}
if (bitmap.isRecycled()) {
throw new IllegalArgumentException("bitmap is recycled");
}
if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
throw new IllegalArgumentException("invalid Bitmap format");
}
}
It doesn't look like it's recycling anything. Are you sure you are not loading a huge bitmap into memory? Two calls of those are more than enough to guarantee a huge explosion in your app, if not just one (I've seen it happen many times in my app). Remember, restarting your activity does not mean restarting your proccess.
Run the Android Profiler before the first load and check how much memory it takes.
Also, you can cache and reuse bitmaps yourself.
add a comment |
Implementation of texImage2D looks like this:
public static void texImage2D(int target, int level, int internalformat,
Bitmap bitmap, int border) {
if (bitmap == null) {
throw new NullPointerException("texImage2D can't be used with a null Bitmap");
}
if (bitmap.isRecycled()) {
throw new IllegalArgumentException("bitmap is recycled");
}
if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
throw new IllegalArgumentException("invalid Bitmap format");
}
}
It doesn't look like it's recycling anything. Are you sure you are not loading a huge bitmap into memory? Two calls of those are more than enough to guarantee a huge explosion in your app, if not just one (I've seen it happen many times in my app). Remember, restarting your activity does not mean restarting your proccess.
Run the Android Profiler before the first load and check how much memory it takes.
Also, you can cache and reuse bitmaps yourself.
add a comment |
Implementation of texImage2D looks like this:
public static void texImage2D(int target, int level, int internalformat,
Bitmap bitmap, int border) {
if (bitmap == null) {
throw new NullPointerException("texImage2D can't be used with a null Bitmap");
}
if (bitmap.isRecycled()) {
throw new IllegalArgumentException("bitmap is recycled");
}
if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
throw new IllegalArgumentException("invalid Bitmap format");
}
}
It doesn't look like it's recycling anything. Are you sure you are not loading a huge bitmap into memory? Two calls of those are more than enough to guarantee a huge explosion in your app, if not just one (I've seen it happen many times in my app). Remember, restarting your activity does not mean restarting your proccess.
Run the Android Profiler before the first load and check how much memory it takes.
Also, you can cache and reuse bitmaps yourself.
Implementation of texImage2D looks like this:
public static void texImage2D(int target, int level, int internalformat,
Bitmap bitmap, int border) {
if (bitmap == null) {
throw new NullPointerException("texImage2D can't be used with a null Bitmap");
}
if (bitmap.isRecycled()) {
throw new IllegalArgumentException("bitmap is recycled");
}
if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
throw new IllegalArgumentException("invalid Bitmap format");
}
}
It doesn't look like it's recycling anything. Are you sure you are not loading a huge bitmap into memory? Two calls of those are more than enough to guarantee a huge explosion in your app, if not just one (I've seen it happen many times in my app). Remember, restarting your activity does not mean restarting your proccess.
Run the Android Profiler before the first load and check how much memory it takes.
Also, you can cache and reuse bitmaps yourself.
answered Nov 19 '18 at 18:11
ReaperReaper
488
488
add a comment |
add a comment |
I solved it (myself) by putting the files into the raw folder of the resource directory, and loading them using
fun loadBitmap(res: Resources, rawId: Int): Bitmap {
val inputStream = BufferedInputStream(res.openRawResource(rawId))
return BitmapFactory.decodeStream(inputStream)
}
and then calling
load(bitmap, linear);
and
bitmap.recycle()
like before.
Luckily those all were png/jpeg files, so I didn't need the additional features of the drawables folder. Using this, they'll automatically use their right resolution.
My Java RAM allocation is now back on 25 MB to 35 MB instead of the 110 MB when using the old way :).
add a comment |
I solved it (myself) by putting the files into the raw folder of the resource directory, and loading them using
fun loadBitmap(res: Resources, rawId: Int): Bitmap {
val inputStream = BufferedInputStream(res.openRawResource(rawId))
return BitmapFactory.decodeStream(inputStream)
}
and then calling
load(bitmap, linear);
and
bitmap.recycle()
like before.
Luckily those all were png/jpeg files, so I didn't need the additional features of the drawables folder. Using this, they'll automatically use their right resolution.
My Java RAM allocation is now back on 25 MB to 35 MB instead of the 110 MB when using the old way :).
add a comment |
I solved it (myself) by putting the files into the raw folder of the resource directory, and loading them using
fun loadBitmap(res: Resources, rawId: Int): Bitmap {
val inputStream = BufferedInputStream(res.openRawResource(rawId))
return BitmapFactory.decodeStream(inputStream)
}
and then calling
load(bitmap, linear);
and
bitmap.recycle()
like before.
Luckily those all were png/jpeg files, so I didn't need the additional features of the drawables folder. Using this, they'll automatically use their right resolution.
My Java RAM allocation is now back on 25 MB to 35 MB instead of the 110 MB when using the old way :).
I solved it (myself) by putting the files into the raw folder of the resource directory, and loading them using
fun loadBitmap(res: Resources, rawId: Int): Bitmap {
val inputStream = BufferedInputStream(res.openRawResource(rawId))
return BitmapFactory.decodeStream(inputStream)
}
and then calling
load(bitmap, linear);
and
bitmap.recycle()
like before.
Luckily those all were png/jpeg files, so I didn't need the additional features of the drawables folder. Using this, they'll automatically use their right resolution.
My Java RAM allocation is now back on 25 MB to 35 MB instead of the 110 MB when using the old way :).
answered Nov 19 '18 at 19:29
Antonio NoackAntonio Noack
111
111
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53379963%2fandroid-resources-gc-issue%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
where do you use this?
– petey
Nov 19 '18 at 18:03