java.lang.StackOverflowError: stack size 1038kb

I'm making an algorithm that converts a bitmap leaving it grayscale.

I managed to do using for but would like to do it recursively.


Using for (this is working fine)

//BUTTON - ON CLICK . . .
public void go(View v){
    //BM_3 É UM BITMAP, VARIAVEL GLOBAL QUE JÁ POSSUI UMA IMAGEM EM SEU CONTEUDO . . .
    bm_3 = bm_3.copy(Bitmap.Config.ARGB_8888, true);

    for (int x = 0; x < bm_3.getWidth(); x++){
        for (int y = 0; y < bm_3.getHeight(); y++) {

            String hex = Integer.toHexString(bm_3.getPixel(x, y));

            if(hex.length() == 8) {
                String hexX = "#" + convert_Hex_to_grey("" + hex.charAt(0) + hex.charAt(1),
                                                        "" + hex.charAt(2) + hex.charAt(3),
                                                        "" + hex.charAt(4) + hex.charAt(5),
                                                        "" + hex.charAt(6) + hex.charAt(7));

                bm_3.setPixel(x, y, Color.parseColor(hexX));
            }
        }
    }
    //IMG É UMA IMAGEVIEW . . .
    img.setImageBitmap(bm_3);
}

Based on the algorithm above, I tried to implement the same recursively. However, it is showing error of java.lang.StackOverflowError: stack size 1038KB


Using recursion (java.lang.StackOverflowError)

Recursion

private Bitmap grey_scale(int x, int y, Bitmap bm_3) {
        //IF PARA PERCORRER TODO Y . . .
        if (y < bm_3.getHeight()) {
            String hex = Integer.toHexString(bm_3.getPixel(x, y));
            if (hex.length() == 8) {
                String hexX = "#" + convert_Hex_to_grey("" + hex.charAt(0) + hex.charAt(1),
                                                        "" + hex.charAt(2) + hex.charAt(3),
                                                        "" + hex.charAt(4) + hex.charAt(5),
                                                        "" + hex.charAt(6) + hex.charAt(7));


                bm_3.setPixel(x, y, Color.parseColor(hexX));
            }
            //O ERRO OCORRE NESTE RETURN ! ! !
            return grey_scale(x, y+1, bm_3);

        }
        //IF PARA PERCORRER TODO X, ZERANDO Y A CADA TROCA DE X.
        if (x < bm_3.getWidth()) {
            return grey_scale(x+1, 0, bm_3);
        }
    //RETORNA BITMAP
    return bm_3;
}

BUTTON ON CLICK THAT CALLS RECURSION

public void go(View v){

    bm_3 = bm_3.copy(Bitmap.Config.ARGB_8888, true);
    //FAZ RECURSAO DENTRO DE UMA THREAD . . .
    new Thread(new Runnable() {
        @Override
        public void run() {
            //CHAMA A RECURSAO
            bm_3 = grey_scale(0, 0, bm_3);

            //VOLTA PRA THREAD PRINCIPAL PARA ATUALIZAR O IMAGEVIEW . . .
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    img.setImageBitmap(bm_3);
                }
            });
        }
    }).start();
}
Author: Comunidade, 2017-09-13

1 answers

The problem here is the size of the recursion. Its recursion is approximately 621 thousand calls, given the image of 788 x 788.

Each recursive call does at least insert the call's arguments into the stack. In the case, it is two integers and a reference; the integers are 4 bytes each, the reference is 8 or 4 bytes (8 bytes for 64 bits and 4 bytes for 32 bits). Therefore, you put at least 12 bytes for each recursive call. Thus, not considering other factors, the minimum required for the stack is about 10 or 12 megabytes of recursive call arguments only. Who knows how much more of other information?

Anyway, maybe with 64 megabytes of stack? To determine this value, the virtual machine argument -Xss 64M defines this. Source

Well, the AP is having the problem running on Android Studio, so trying to do these tweaks with the JVM may not result in anything.


PS: just before finishing the writing this answer, I saw that setting the stack size on the thread didn't work. I'll inspect a bit more and then edit the answer with what I find

 3
Author: Jefferson Quesado, 2019-09-09 17:18:50