0

I am using the method described in the accepted answer in this post How to programmatically take a screenshot in Android? to take a screenshot. I change that method only in that I don't use the openScreenshot(imageFile) method used in that post because I just need the image file to be on the storage and I don't need to open it immediately.

I use this method as a public static void method because I need it in several parts of my app. The problem is that I have memory leaks and after using the method 5-6 times consequently I get this type of error:

java.lang.OutOfMemoryError: Failed to allocate a 3686412 byte allocation with 899204 free bytes and 878KB until OOM

I tried the solution to increase the available memory by setting android:largeHeap="true" in the manifest.xml. file. But this only postpones the error 2-3 times more.

I also tried to firstly clear the bitmap and then recycle it by adding this:

    Canvas bitmapCanvas = new Canvas(bitmap);
    bitmap.eraseColor(Color.TRANSPARENT);
    bitmapCanvas.setBitmap(null);
    bitmapCanvas = null;
    bitmap.recycle();

both before and after

    outputStream.flush();
    outputStream.close();

but nothing changes. Any suggestions please?

PS Here is the full method:

public static void takeScreenshot(View v1, File f, Context context) {
    Date now = new Date();
    android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);

    try {
        String mPath = f.getPath();

        // create bitmap screen capture
        v1.setDrawingCacheEnabled(true);
        Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());

        v1.setDrawingCacheEnabled(false);

        File imageFile = new File(mPath);

        FileOutputStream outputStream = new FileOutputStream(imageFile);
        int quality = 100;
        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);


        //trying to release memory
        Canvas bitmapCanvas = new Canvas(bitmap);
        bitmap.eraseColor(Color.TRANSPARENT);
        bitmapCanvas.setBitmap(null);
        bitmapCanvas = null;
        bitmap.recycle();


        outputStream.flush();
        outputStream.close();



} catch (Throwable e) {
        // Several error may come out with file handling or OOM
        e.printStackTrace();
        Toast.makeText(context, "An error occurred!" + e.getMessage().toString() , Toast.LENGTH_LONG).show();
    }
}

and here is how i call it(the method is placed in a Class named Commonmethods

 View v1 = getWindow().getDecorView().getRootView();
 File imagefile = new File(Environment.getExternalStorageDirectory().getPath() + "/my_files/" + "screenshot.png");
 CommonMethods.takeScreenshot(v1, imagefile, this);
Cœur
  • 37,241
  • 25
  • 195
  • 267
geo
  • 517
  • 1
  • 9
  • 28
  • I think it must be some problem with the `static` flag. Making a method static will keep it from getting Garbage Collected and keep it in the memory at all times. Try not to use it and tell me what you see. – Siddharth Venu Oct 09 '16 at 06:31
  • @SiddharthVenu I copied and used the method in one of the activities that use it as a private method but the problem remains. – geo Oct 09 '16 at 06:42
  • in which device are you testing ? whats the memory limit of the device ? – Kenshin Oct 09 '16 at 07:21
  • @Arun This is the device:http://www.gsmarena.com/motorola_moto_g_4g-6355.php – geo Oct 09 '16 at 07:24
  • its trying to occupy 3mb for each snap and thats too much..If you are really concerned about the quality and dimension, well fine!. Otherwise you could try reducing it... If recyle() works as expected, you shouldn't see the OOM. It would be helpful if you could paste your entire function – Kenshin Oct 09 '16 at 07:43
  • @Arun. I wouldn't mind much decreasing image quality. But the leak would still be a leak – geo Oct 09 '16 at 07:55
  • I think the whole problem with your code is following this comment "//trying to release memory" Why do we need Canvas bitmapCanvas = new Canvas(bitmap); ? You should be doing this bitmap.recycle(); bitmap = null; – Kenshin Oct 09 '16 at 08:09
  • setting it to null is to assist the GC to quickly collect your reference. – Kenshin Oct 09 '16 at 08:10
  • @Arun I placed re canvas related code just to try if it works and it doesn't. The problem exists with or without the canvas code. I also added bitmap=null as you wrote, but still nothing. – geo Oct 09 '16 at 10:19
  • I just tried your code in old samsung mega 5.8 and there is no memory leak in it. – Kenshin Oct 09 '16 at 12:39
  • your code may be leaking somewhere else after capture...connect device and use memory analyzer – Kenshin Oct 09 '16 at 12:41
  • This is my flow of your code: FileOutputStream outputStream = new FileOutputStream(imageFile); int quality = 100; bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream); outputStream.flush(); outputStream.close(); //trying to release memory /*Canvas bitmapCanvas = new Canvas(bitmap); bitmap.eraseColor(Color.TRANSPARENT); bitmapCanvas.setBitmap(null); bitmapCanvas = null;*/ bitmap.recycle(); bitmap = null; – Kenshin Oct 09 '16 at 13:06
  • There is no memory leak in the code you posted, if must be somewhere else. – Xaver Kapeller Oct 09 '16 at 13:45
  • I am having a similar problem, taking a screenshot of a view in main thread, than in rxjava saving the bitmap to disk. Looks like a reference to bitmap hangs in rxjava, but not sure yet, still investigating. – Michail Lukow Jul 15 '19 at 08:53

1 Answers1

0

I tried your code with minor changes by shifting position of stream and adding bitmap.recycle() followed by assigning it to null and I couldn't find any memory leak with it.

Your screen capture code is working fine...

I am attaching the code snippet I tried in android studio for your reference. Also attached memory log

Please check what's happening after capturing snap

package com.fun.test;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


    }

    public void capture(View view) {
        View v1 = getWindow().getDecorView().getRootView();
        File imagefile = new File(Environment.getExternalStorageDirectory().getPath()+ "/screenshot.png");
        try {
            imagefile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        takeScreenshot(v1, imagefile, this);
    }

    public void takeScreenshot(View v1, File f, Context context) {
        Date now = new Date();
        android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);

        try {
            String mPath = f.getPath();

            // create bitmap screen capture
            v1.setDrawingCacheEnabled(true);
            Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());

            v1.setDrawingCacheEnabled(false);

            File imageFile = new File(mPath);

            FileOutputStream outputStream = new FileOutputStream(imageFile);
            int quality = 100;
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);

            outputStream.flush();
            outputStream.close();

            //trying to release memory
            /*Canvas bitmapCanvas = new Canvas(bitmap);
            bitmap.eraseColor(Color.TRANSPARENT);
            bitmapCanvas.setBitmap(null);
            bitmapCanvas = null;*/
            bitmap.recycle();
            bitmap = null;




        } catch (Throwable e) {
            // Several error may come out with file handling or OOM
            e.printStackTrace();
            Toast.makeText(context, "An error occurred!" + e.getMessage().toString() , Toast.LENGTH_LONG).show();
        }
    }
}

And this is the memory allocation log from android studio

10-09 19:08:17.195 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 6 mFalseSizeCnt:0
10-09 19:08:17.275 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 245K, 23% free 7702K/9884K, paused 62ms, total 63ms
10-09 19:08:17.285 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 11.386MB for 2073616-byte allocation
10-09 19:08:17.295 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 5K, 19% free 9722K/11912K, paused 16ms, total 16ms
10-09 19:08:17.335 28618-28622/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=4194304, min=1048576, ut=568
10-09 19:08:17.335 28618-28622/com.fun.test D/dalvikvm: GC_CONCURRENT freed <1K, 19% free 9722K/11912K, paused 2ms+16ms, total 38ms
10-09 19:08:17.335 28618-28618/com.fun.test D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 27ms
10-09 19:08:17.345 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 13.359MB for 2073616-byte allocation
10-09 19:08:17.355 28618-28627/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=6291456, min=1572864, ut=368
10-09 19:08:17.365 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 16% free 11747K/13940K, paused 26ms, total 26ms


10-09 19:08:37.085 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 3 mFalseSizeCnt:0
10-09 19:08:37.105 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 8126K, 23% free 7698K/9884K, paused 19ms, total 19ms
10-09 19:08:37.115 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 11.382MB for 2073616-byte allocation
10-09 19:08:37.125 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 19% free 9723K/11912K, paused 14ms, total 14ms
10-09 19:08:37.145 28618-28622/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=4194304, min=1048576, ut=568
10-09 19:08:37.145 28618-28622/com.fun.test D/dalvikvm: GC_CONCURRENT freed <1K, 19% free 9723K/11912K, paused 3ms+2ms, total 20ms
10-09 19:08:37.145 28618-28618/com.fun.test D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 10ms
10-09 19:08:37.145 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 13.360MB for 2073616-byte allocation
10-09 19:08:37.165 28618-28627/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=6291456, min=1572864, ut=368
10-09 19:08:37.165 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 16% free 11748K/13940K, paused 12ms, total 12ms


10-09 19:08:51.208 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 3 mFalseSizeCnt:0
10-09 19:08:51.228 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 8124K, 23% free 7698K/9884K, paused 20ms, total 20ms
10-09 19:08:51.238 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 11.382MB for 2073616-byte allocation
10-09 19:08:51.248 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 19% free 9723K/11912K, paused 15ms, total 15ms
10-09 19:08:51.268 28618-28622/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=4194304, min=1048576, ut=568
10-09 19:08:51.268 28618-28622/com.fun.test D/dalvikvm: GC_CONCURRENT freed <1K, 19% free 9723K/11912K, paused 2ms+1ms, total 19ms
10-09 19:08:51.268 28618-28618/com.fun.test D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 11ms
10-09 19:08:51.268 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 13.360MB for 2073616-byte allocation
10-09 19:08:51.288 28618-28618/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=6291456, min=1572864, ut=368
10-09 19:08:51.288 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 16% free 11748K/13940K, paused 13ms, total 13ms


10-09 19:08:58.676 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 4 mFalseSizeCnt:0
10-09 19:08:59.516 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 2 mFalseSizeCnt:0
10-09 19:08:59.546 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 8123K, 23% free 7698K/9884K, paused 19ms, total 20ms
10-09 19:08:59.546 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 11.382MB for 2073616-byte allocation
10-09 19:08:59.566 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 19% free 9723K/11912K, paused 15ms, total 15ms
10-09 19:08:59.586 28618-28622/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=4194304, min=1048576, ut=568
10-09 19:08:59.586 28618-28622/com.fun.test D/dalvikvm: GC_CONCURRENT freed <1K, 19% free 9723K/11912K, paused 3ms+2ms, total 19ms
10-09 19:08:59.586 28618-28618/com.fun.test D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 10ms
10-09 19:08:59.586 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 13.360MB for 2073616-byte allocation
10-09 19:08:59.606 28618-28627/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=6291456, min=1572864, ut=368
10-09 19:08:59.606 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 16% free 11748K/13940K, paused 16ms, total 16ms


10-09 19:09:08.085 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 5 mFalseSizeCnt:0
10-09 19:09:09.066 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 3 mFalseSizeCnt:0
10-09 19:09:09.096 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 8123K, 23% free 7698K/9884K, paused 18ms, total 18ms
10-09 19:09:09.096 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 11.382MB for 2073616-byte allocation
10-09 19:09:09.116 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 19% free 9723K/11912K, paused 15ms, total 15ms
10-09 19:09:09.136 28618-28622/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=4194304, min=1048576, ut=568
10-09 19:09:09.136 28618-28622/com.fun.test D/dalvikvm: GC_CONCURRENT freed <1K, 19% free 9723K/11912K, paused 3ms+1ms, total 20ms
10-09 19:09:09.136 28618-28618/com.fun.test D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 11ms
10-09 19:09:09.136 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 13.360MB for 2073616-byte allocation
10-09 19:09:09.156 28618-28627/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=6291456, min=1572864, ut=368
10-09 19:09:09.156 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 16% free 11748K/13940K, paused 15ms, total 15ms


10-09 19:09:16.163 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 2 mFalseSizeCnt:0
10-09 19:09:18.605 28618-28618/com.fun.test D/GestureDetector: [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 4 mFalseSizeCnt:0
10-09 19:09:18.645 28618-28618/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed 8123K, 23% free 7698K/9884K, paused 31ms, total 31ms
10-09 19:09:18.645 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 11.383MB for 2073616-byte allocation
10-09 19:09:18.655 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 19% free 9723K/11912K, paused 15ms, total 15ms
10-09 19:09:18.685 28618-28622/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=4194304, min=1048576, ut=568
10-09 19:09:18.685 28618-28622/com.fun.test D/dalvikvm: GC_CONCURRENT freed <1K, 19% free 9723K/11912K, paused 3ms+1ms, total 21ms
10-09 19:09:18.685 28618-28618/com.fun.test D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 12ms
10-09 19:09:18.685 28618-28618/com.fun.test I/dalvikvm-heap: Grow heap (frag case) to 13.360MB for 2073616-byte allocation
10-09 19:09:18.695 28618-28627/com.fun.test E/dalvikvm: adjustAdaptiveCoef max=6291456, min=1572864, ut=368
10-09 19:09:18.695 28618-28627/com.fun.test D/dalvikvm: GC_FOR_ALLOC freed <1K, 16% free 11748K/13940K, paused 14ms, total 14ms
Kenshin
  • 1,030
  • 2
  • 12
  • 41
  • You are right, The code is right. It must be something wrong with the class that calls the screenshot method, and not the screenshot method itself. Thanks for the interest in helping. – geo Oct 12 '16 at 08:35