본문 바로가기

안드로이드/Kotlin

8. Effective Kotlin - 사용하지 않는 객체의 레퍼런스를 제거하라

사용하지 않는 객체의 레퍼런스를 제거하라

Java와 같은 메모리 관리를 자동으로 해주는 프로그래밍 언어를 사용할 경우, 해제(free)를 따로 고려하지 않는다. 하지만, 메모리 관리를 완전히 무시해버리면 메모리 누수가 발생하여 OOM(Out Of Memory)가 발생한다. 따라서, 필요 없는 객체의 레퍼런스는 명시적으로 끊어주어야 한다.

메모리 문제는 굉장히 사소한 곳에서 발생한다.

class Stack {
    private val elements: Array<Any?> = arrayOfNulls(DEFAULT_CAPACITY)
    private var size = 0

    fun push(e: Any?) {
        ensureCapacity()
        elements[size++] = e
    }

    fun pop(): Any? {
        if (size ==0)
            throw Exception()
        return elements[--size]
    }

    private fun ensureCapacity() {
        if (elements.size == size)
            elements = elements.copyOf(2*size+1)
    }

    companion object {
        private const val DEFAULT_CAPACITY = 16
    }
}

만약 위와 같은 코드에서 1000개의 아이템을 추가하고 999개를 제거한다고 가정하자. elements는 1개 까지만 유효하지만, 단순히 size를 줄여가며 배열의 인덱스로 접근하는 방식이라 실제 element가 제거되지 않아 이는 메모리 누수로 이어진다.

따라서, 다음과 같이 수정이 필요하다.

fun pop(): Any? {
    if (size == 0)
        throw Exception()
    val element = elements[--size]
    element[size] = null
    return element
}

메모리 누수가 발생하는 경우는 "절대 사용하지 않는 객체를 캐시해두는 경우"에도 발생한다. 이 경우에는 Soft Reference를 사용하여, 메모리가 부족해진 상황에서는 할당 해제되도록 하는 것이 방법이다.

화면 위의 Dialog 같은 경우에는 Weak Reference를 사용하는 것이 좋다. Dialog가 나오는 동안에는 GC가 이를 처리하지 않을 것이다. 이후, Dialog가 닫히게 되면 이에 대한 참조를 유지할 필요가 없다. Weak Reference는 GC가 메모리를 수집할 때 반드시 해제된다.