Android Resources GC Issue












0















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.










share|improve this question

























  • where do you use this?

    – petey
    Nov 19 '18 at 18:03
















0















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.










share|improve this question

























  • where do you use this?

    – petey
    Nov 19 '18 at 18:03














0












0








0








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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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



















  • 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












2 Answers
2






active

oldest

votes


















0














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.






share|improve this answer































    0














    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 :).






    share|improve this answer























      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
      });


      }
      });














      draft saved

      draft discarded


















      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









      0














      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.






      share|improve this answer




























        0














        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.






        share|improve this answer


























          0












          0








          0







          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.






          share|improve this answer













          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.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 19 '18 at 18:11









          ReaperReaper

          488




          488

























              0














              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 :).






              share|improve this answer




























                0














                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 :).






                share|improve this answer


























                  0












                  0








                  0







                  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 :).






                  share|improve this answer













                  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 :).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 19 '18 at 19:29









                  Antonio NoackAntonio Noack

                  111




                  111






























                      draft saved

                      draft discarded




















































                      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.




                      draft saved


                      draft discarded














                      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





















































                      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







                      這個網誌中的熱門文章

                      Xamarin.form Move up view when keyboard appear

                      Post-Redirect-Get with Spring WebFlux and Thymeleaf

                      Anylogic : not able to use stopDelay()