[android] 안드로이드에서 메모리 누수를 일으키는 일반적인 실수

안드로이드 앱을 개발하다보면 가끔 메모리 누수(memory leak) 문제에 직면할 수 있습니다. 메모리 누수는 앱의 성능을 떨어뜨리고 결국에는 크래시를 일으킬 수 있기 때문에 중요한 문제입니다. 안드로이드에서 메모리 누수를 일으키는 일반적인 실수를 살펴보고 방지하는 방법에 대해 알아보겠습니다.

1. 정적인 Context 참조

안드로이드 앱에서 Context를 사용할 때, Activity나 Fragment 등의 생명주기와 관련된 객체에 대한 참조를 정적 변수(static variable)나 내부 클래스에 보관하는 것이 메모리 누수를 유발할 수 있습니다. 예를 들어, Activity의 인스턴스를 참조하는 static 변수가 있다면 해당 Activity가 종료되어도 메모리에서 해제되지 않고 계속 남아있을 수 있습니다.

public class MySingleton {
    private static MyActivity sActivity;

    public static void setActivity(MyActivity activity) {
        sActivity = activity;
    }
}

이런 경우에는 약한 참조(Weak Reference)액티비티의 생명주기에 맞춘 참조 해제 등의 방법을 사용하여 메모리 누수를 방지할 수 있습니다.

2. 비동기 작업 관리

안드로이드 앱에서는 네트워크 요청이나 파일 I/O와 같은 비동기 작업을 수행하는 경우가 많습니다. 이때, 비동기 작업이 Activity나 Fragment의 생명주기보다 더 오래 실행되는 경우가 있을 수 있습니다. 이렇게 되면 해당 Activity나 Fragment가 파괴되어도 비동기 작업이 계속 실행되어 메모리 누수를 일으킬 수 있습니다.

public class MyActivity extends AppCompatActivity {
    private AsyncTask mTask;

    public void startTask() {
        mTask = new AsyncTask().execute();
    }

    @Override
    protected void onDestroy() {
        if (mTask != null) {
            mTask.cancel(true);
        }
        super.onDestroy();
    }
}

이를 방지하기 위해 Activity나 Fragment의 생명주기에 맞춰 비동기 작업을 취소하거나, ViewModel 등의 구성 요소를 활용하여 생명주기를 관리할 수 있습니다.

3. 리스너 등록 해제

안드로이드에서는 리스너를 등록한 후에 해당 활동이 종료될 때 명시적으로 이를 해제하지 않는 경우가 있습니다. 이때는 해당 활동이 종료되지 않은 상태에서도 메모리를 계속 점유하게 되는데, 이는 결국 메모리 누수로 이어질 수 있습니다.

public class MyActivity extends AppCompatActivity {
    private SensorManager mSensorManager;
    private SensorEventListener mSensorListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mSensorListener = new SensorEventListener() {
            // ...
        };
        mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onDestroy() {
        mSensorManager.unregisterListener(mSensorListener);
        super.onDestroy();
    }
}

리스너를 등록할 때는 상응하는 생명주기 메서드에서 명시적으로 해제해야 합니다.

결론

안드로이드 앱을 개발할 때 메모리 누수 문제는 어려운 문제가 될 수 있지만, 약한 참조를 활용하고 생명주기를 잘 관리함으로써 이러한 문제를 방지할 수 있습니다. 또한, Linter나 프로파일링 도구를 활용하여 메모리 누수를 분석함으로써 미리 예방하는 것도 중요합니다.

참고 자료: