๊พธ์ค€ํ•จ์ด ์ง„๋ฆฌ๋‹ค!!

์–ด์ œ๋ณด๋‹ค ๋ฐœ์ „ํ•œ ์˜ค๋Š˜์ด ๋˜๊ณ ํ”ˆ ๐Ÿง‘๐Ÿปโ€๐Ÿ’ป ์˜ ๋ธ”๋กœ๊ทธ

Android/Java

[Java][Android] ์•ˆ๋“œ๋กœ์ด๋“œ InputMethodManager ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜(leak) ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

๋ށ์š” 2022. 7. 13. 14:41

์˜ค๋Š˜์€ ํšŒ์‚ฌ์—์„œ ๊ทผ๋ฌด์ค‘์— ๋ฐœ๊ฒฌํ•œ InputMethodManager์— ๊ด€๋ จํ•œ Memory Leak์— ๋Œ€ํ•ด ํฌ์ŠคํŒ… ํ•˜๋ คํ•ฉ๋‹ˆ๋‹ค.

์ž์ฒด์ ์œผ๋กœ ์•ฑ์— ๋Œ€ํ•ด ๋ฉ”๋ชจ๋ฆฌ Leak๋ถ€๋ถ„์ด ์žˆ๋Š”์ง€ ํ™•์ธ์ค‘ dumpsys ํ™•์ธ๊ฒฐ๊ณผ GC๊ฐ€ ๋Œ์•„๋„ Activites์™€ View๊ฐ€ ๋ฆด๋ฆฌ์ฆˆ ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ์ ์ด ๋ฐœ๊ฒฌ๋˜์–ด ์•ฝ 1๋‹ฌ ๋™์•ˆ ํ•ด๋งธ์Šต๋‹ˆ๋‹ค..

ํ˜„์žฌ ์ œ๊ฐ€ ๊ทผ๋ฌดํ•˜๋Š” ํšŒ์‚ฌ์˜ ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „์€ Android4.4(KitKat)๋กœ ๋งค์šฐ ์˜›๋‚  ๋ฒ„์ „์ด๋‹ค๋ณด๋‹ˆ Profiler๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•ด ๋” ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ๋˜๊ฒƒ์ด๊ณ  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•  ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์„๊ฒ๋‹ˆ๋‹ค. (๋ณ€๋ช… ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.)

Profiler๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ฒ„์ „์—์„œ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ดํ›„ ์ถ”๊ฐ€์ ์œผ๋กœ ํฌ์ŠคํŒ… ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

Profiler ํ™•์ธ ๊ฒฐ๊ณผ ๋ฉ”๋ชจ๋ฆฌ Leak์ด 2๊ฑด ๋ฐœ์ƒ ํ•˜์˜€๊ณ  ๋ชจ๋‘ InputMethodManager์—์„œ 'mCurRootView' , 'mServedView , mNextServedView'๋ฅผ ์ฐธ์กฐ ํ•˜๊ณ  ์žˆ์–ด ๋ฐœ์ƒํ•œ๊ฒƒ์œผ๋กœ ํ™•์ธ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 

 

์œ„ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋Š” ์›์ธ์€ Fragment๋‚˜ RecyclerView๋“ฑ์˜ ๊ณ„์ธต ๊ตฌ์กฐ์˜ View๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ์ข…๋ฃŒ ์ง์ „ Focus๋˜์–ด ์žˆ๋˜ View์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ํ•ด์ œํ•˜์ง€ ๋ชปํ•˜๊ณ  ์•ˆ๋“œ๋กœ์ด๋“œ F/W์—์„œ ์žก๊ณ ์žˆ์–ด ๋ฐœ์ƒํ•˜๋Š”๊ฒƒ์ด๋ฉฐ api level 15 ~ 23์—์„œ ๋‚˜ํƒ€๋‚˜๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ์ž์ฒด ๋ฒ„๊ทธ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค..;

(๊ตฌ๊ธ€์—์„œ๋„ ์•„์ง ํ•ด๋‹น ๋ฒ„๊ทธ์— ๋Œ€ํ•ด ์ˆ˜์ • ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค๋Š”..) 

 

๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋‚˜์ค‘์— ์‹œ๊ฐ„์ด ์ง€๋‚˜ View๊ฐ€ ํ•„์š” ์—†๋‹ค๊ณ  ํŒ๋‹จ ๋ ๋•Œ ์•ˆ๋“œ๋กœ์ด๋“œ ์ž์ฒด์ ์œผ๋กœ ๋ฆด๋ฆฌ์ฆˆ ์‹œํ‚จ๋‹ค๊ณ ๋Š” ํ•˜๋‚˜.. ์ €๋Š” ๋‹น์žฅ ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด๋‹ˆ 2๊ฐ€์ง€ ์ •๋„์˜ ๋ฐฉ๋ฒ•์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

1. ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ dummy activity๋ฅผ start์‹œํ‚จํ›„ ๋ฐ”๋กœ ์ข…๋ฃŒ ์‹œ์ผœ focus๋ฅผ ๋ฆด๋ฆฌ์ฆˆ ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•

์œ„ ๋ฐฉ๋ฒ•์€ ๋™์ž‘์ƒ ๊นœ๋นก๊ฑฐ๋ฆผ๋“ฑ์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์œผ๋กœ ๋ณด์—ฌ ์‹œ๋„ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

 

2. ์ข…๋ฃŒ ์‹œ์ (onDestroy)์— InputMethodManager ์„œ๋น„์Šค๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์™€ ์œ„ instance๋“ค์„ ์ง์ ‘ ๋ฆด๋ฆฌ์ฆˆ ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•

์ €๋Š” ์œ„ ๋ฐฉ๋ฒ•์„ ํƒํ•˜์˜€๊ณ  ๊ฒฐ๋ก ์ ์œผ๋กœ๋Š” dumpsys์™€ Profiler์ƒ ๋ฆด๋ฆฌ์ฆˆ๊ฐ€ ๋˜์ง€ ์•Š๋˜ ๋ถ€๋ถ„์ด ํ•ด๊ฒฐ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

๋ฐฉ๋ฒ•์€ ์•„๋ž˜ ์ฐธ๊ณ  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

 

public static void fixInputMethodMemoryLeak(Context context) {
        if (context == null)
            return;
        //InputMethodManager ๊ฐ€์ ธ์˜ค๊ธฐ    
        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager == null)
            return;

        String[] viewArr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
        Field field;
        Object fieldObj;
        for (String view: viewArr) {
            try {
                field = inputMethodManager.getClass().getDeclaredField(view);
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                fieldObj = field.get(inputMethodManager);
                if (fieldObj != null && fieldObj instanceof View) {
                    View fieldView = (View) fieldObj;
                    if (fieldView.getContext() == context) {
                       //istance null๋กœ ๋ฆด๋ฆฌ์ฆˆ ์‹œํ‚ค๋Š” ๋™์ž‘
                       field.set(inputMethodManager, null);
                    } else {
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

์œ„์™€ ๊ฐ™์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ•˜๋‚˜ ์ž‘์„ฑํ•œ ํ›„

@Override
    protected void onDestroy() {
        fixInputMethodMemoryLeak(this);
        super.onDestroy();
    }

์•„๋ž˜์™€ ๊ฐ™์ด ํ˜ธ์ถœํ•˜์—ฌ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ super์ „์— ํ˜ธ์ถœ ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค. super ์ดํ›„์— ํ˜ธ์ถœ ์‹œ ์ด๋ฏธ finish()๋™์ž‘์ด ์ˆ˜ํ–‰๋˜๊ธฐ์— ์ธ์Šคํ„ด์Šค๋“ค์„ ๋ฆด๋ฆฌ์ฆˆ ํ•˜์ง€ ์•Š๊ณ  ์•ฑ์ด ์ข…๋ฃŒ ๋ฉ๋‹ˆ๋‹ค..; (์ด๊ฑธ๋กœ๋„ ์กฐ๊ธˆ ๊ณ ์ƒํ•จ)

 

์œ„ ์™€ ๊ฐ™์ด Memry Leak์„ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

'Android > Java' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Java][Android] Android ViewTreeObserVer onGlobalLayoutListener ํ™œ์šฉํ•˜๊ธฐ  (0) 2022.08.24