앱 메모리 관리

이 페이지에서는 사전에 앱 내 메모리 사용량을 줄이는 방법을 설명합니다. Android 운영체제에서 메모리를 관리하는 방법에 관한 자세한 내용은 메모리 관리 개요 를 참고하세요.

랜덤 액세스 메모리 (RAM)는 모든 소프트웨어 개발 환경에서 중요한 리소스이며 실제 메모리의 제약이 많은 모바일 운영체제에서는 더욱 중요합니다. Android 런타임 (ART)과 Dalvik 가상 머신에서 일상적인 가비지 컬렉션을 실행하지만, 그래도 앱에서 메모리를 할당하고 해제하는 시점과 위치를 무시할 수는 없습니다. 일반적으로 정적 멤버 변수에서 객체 참조를 유지하여 발생하는 메모리 누수를 방지하고 수명 주기 콜백에서 정의한 대로 적절한 시점에 모든 Reference 객체를 해제하는 작업은 계속해야 합니다.

앱의 코드 및 리소스 공간 줄이기

코드 내의 일부 리소스와 라이브러리는 사용자가 인식하지 못하는 사이에 메모리를 소비할 수 있습니다. 서드 파티 라이브러리 또는 삽입된 리소스를 비롯하여 APK의 전체 크기는 앱에서 사용하는 메모리 양에 영향을 줄 수 있습니다. 코드에서 중복되거나 불필요하거나 지나치게 커진 구성요소, 리소스, 라이브러리를 삭제하여 앱의 메모리 소비를 개선할 수 있습니다.

R8을 사용 설정하여 전체 앱 크기 줄이기

컴파일된 애플리케이션 코드는 런타임 메모리 공간의 활성 부분입니다. 실행 시 모든 클래스, 메서드, 라이브러리 종속 항목, 문자열 상수를 RAM에 로드해야 합니다. 컴파일된 코드베이스가 클수록 앱에 필요한 실제 RAM이 많아집니다.

R8을 사용하여 앱의 메모리 사용량을 줄일 수 있습니다. R8은 일반적으로 APK 크기를 줄이는 것으로 알려져 있지만 런타임 메모리 (RAM)에 직접적이고 긍정적인 영향을 미칩니다. R8은 앱의 바이트 코드를 분석하여 데드 코드를 삭제하고, 중복 클래스를 병합하고, 메서드를 인라인 처리하고, 식별자를 축소합니다. APK에서 RAM으로 컴파일된 바이트 코드를 더 적게 로드하면 앱의 전반적인 기준 메모리 사용량이 줄어듭니다. 또한 클래스, 메서드, 필드 이름을 더 짧은 식별자로 축소하면 RAM 오버헤드가 직접적으로 줄어듭니다. 클래스 병합 및 광범위한 메서드 인라인 처리와 같은 최적화는 비용이 많이 드는 런타임 조회 및 할당 패턴을 대체하여 최적화된 힙 및 스택 메모리를 생성합니다.

keep 규칙 이해

keep 규칙은 최적화 중에 보존할 코드 부분을 R8에 알려주는 구성 안내로, 앱에서 사용하는 코드가 삭제되거나 축소되지 않도록 합니다. 자세한 내용은 keep 규칙 개요를 참고하세요.

잘못 작성된 keep 규칙은 R8이 코드베이스의 많은 부분을 최적화하지 못하도록 합니다. 너무 광범위한 keep 규칙을 피하고 다음 권장사항을 따르세요.

  • 피해야 할 전역 규칙:
    • -dontoptimize: 전체 앱의 최적화를 완전히 사용 중지하여 더 크고 느린 실행 파일을 생성합니다.
    • -dontshrink: 사용하지 않는 코드와 리소스의 삭제를 방지합니다.
    • -dontobfuscate: 이름 축소를 방지하여 귀중한 메모리 절약 (특히 대규모 앱에서)을 놓칩니다.
  • 패키지 전체 와일드카드 피하기: -keep class com.example.package.** { *; }와 같은 광범위한 규칙은 R8이 해당 패키지의 모든 클래스, 필드 및 메서드를 보존하도록 합니다. 이렇게 하면 해당 패키지에서 R8이 코드를 삭제, 최적화, 축소하는 기능이 완전히 중지됩니다.

  • 기본 R8 구성 파일 사용: 항상 proguard-android-optimize.txt를 사용하세요.

keep 규칙 작성에 관한 자세한 내용은 keep 규칙 개요를 참고하세요. 사용하고 피해야 할 특정 패턴은 keep 규칙 권장사항을 참고하세요.

R8 구성 분석기는 R8 구성과 각 keep 규칙이 앱에 미치는 영향을 파악할 수 있는 정보를 제공합니다. 최적화를 차단하는 규칙을 식별하는 방법에 관한 자세한 내용은 R8 구성 분석기를 참고하세요.

외부 라이브러리 사용 관련 주의사항

외부 라이브러리 코드는 모바일 환경을 위해 작성되지 않는 경우가 많으므로 모바일 클라이언트에서 작업하는 데 비효율적일 수 있습니다. 외부 라이브러리를 사용하는 경우 휴대기기에 맞게 라이브러리를 최적화해야 할 수 있습니다. 이 작업을 미리 계획하고 사용하기 전에 코드 크기와 RAM이 차지하는 공간 측면에서 라이브러리를 분석하세요.

일부 모바일에 최적화된 라이브러리도 다른 구현으로 인해 문제를 일으키는 경우가 있습니다. 예를 들어, 한 라이브러리는 라이트 protobuf를 사용하고 다른 라이브러리는 마이크로 protobuf를 사용하면 결과적으로 앱에 두 가지 다른 protobuf 구현이 존재합니다. 이러한 문제는 로깅, 분석, 이미지 로드 프레임워크, 캐싱, 그 밖에 예상하지 못한 여러 곳의 다양한 구현에서 발생할 수 있습니다.

R8을 사용하여 앱을 최적화하면 종속 항목에서 사용하지 않는 코드를 삭제할 수 있지만, 그 효과는 라이브러리의 내부 구성에 의해 제한되는 경우가 많습니다. 예를 들어, 광범위한 keep 규칙 또는 라이브러리 내에서 리플렉션 사용은 R8이 코드를 축소하지 못하도록 하여 메모리 공간이 더 커질 수 있습니다. 효율적인 라이브러리 선택 전략은 라이브러리 현명하게 선택하기를 참고하세요.

수십 가지 기능 중 한두 가지만 사용하기 위해 공유 라이브러리를 사용하지 마세요. 사용하지 않는 많은 양의 코드와 오버헤드가 발생해서는 안 됩니다. 라이브러리 사용 여부를 고려할 때 필요한 내용과 확실히 일치하는 구현을 찾으세요. 또는 구현을 직접 만드는 방법도 있습니다.

종속 항목 삽입에 Hilt 또는 Dagger 2 사용

종속 항목 삽입 프레임워크는 작성하는 코드를 단순화하고 테스트 및 기타 구성 변경에 유용한 적응형 환경을 제공합니다.

앱에서 종속 항목 삽입 프레임워크를 사용하려는 경우 Hilt 또는 Dagger를 사용하는 것이 좋습니다. Hilt는 Dagger를 기반으로 실행되는 Android용 종속 항목 삽입 라이브러리입니다. Dagger는 앱 코드를 검색하는 데 리플렉션을 사용하지 않습니다. 불필요한 런타임 비용이나 메모리 사용 없이 Android 앱에서 Dagger의 정적 컴파일 시간 구현을 사용할 수 있습니다.

리플렉션을 사용하는 기타 종속 항목 삽입 프레임워크는 코드에서 주석을 검색하여 프로세스를 초기화합니다. 이 프로세스에 CPU 주기와 RAM이 훨씬 더 많이 필요할 수 있으며 앱이 시작될 때 현저한 지연이 발생할 수 있습니다.

종속 항목 삽입을 사용할 때는 객체의 범위가 적절하게 지정되도록 하여 메모리 누수를 방지하는 데 주의하세요. 잘못된 수명 주기에 객체를 바인딩하여 필요 이상으로 객체를 유지하면 메모리 누수가 발생할 수 있습니다.

의도적으로 이미지 로드하기

그래픽 비트맵은 일반적으로 앱의 메모리에 상주하는 가장 큰 공통 객체입니다. JPEG와 같은 압축된 파일로 작업하는 경우에도 화면에 표시하려면 파일을 압축되지 않은 비트맵으로 확장해야 합니다. 작은 압축 이미지 파일은 매우 큰 비트맵으로 확장될 수 있습니다.

예를 들어, 대부분의 비트맵은 ARGB_8888 구성을 사용합니다. 즉, 각 픽셀에는 4바이트의 메모리(빨간색, 녹색, 파란색, 알파(투명도) 각각 1바이트)가 필요합니다. 100KB JPEG가 있고 이를 1, 000×1,000픽셀 뷰에 표시하는 경우 비트맵에는 1,000, 000픽셀 각각에 4바이트가 필요하며 총 4MB의 메모리가 추가됩니다.

이미지 사용을 최적화하기 위해 할 수 있는 몇 가지 작업이 있습니다. 예를 들어, 이미지 로드 라이브러리를 사용하면 필요하지 않을 때 메모리를 해제할 수 있습니다. 이미지를 효율적으로 처리하는 방법에 관한 자세한 내용은 비트맵 이미지 최적화를 참고하세요.

사용 가능한 메모리 및 메모리 사용량 모니터링

앱의 메모리 사용량 문제를 해결하려면 먼저 문제를 찾아야 합니다. Android 스튜디오 메모리 프로파일러를 사용하면 다음과 같은 방법으로 메모리 문제를 찾고 진단할 수 있습니다.

메모리 프로파일러는 LeakCanary 누수 감지 라이브러리와도 통합됩니다. LeakCanary를 사용하면 메모리 누수 분석을 테스트 기기에서 개발 머신으로 이동하여 워크플로 속도를 크게 높일 수 있습니다. 자세한 내용은 Android 스튜디오 출시 노트를 참고하세요.

프로덕션 앱을 실행하는 사용자의 데이터를 기반으로 메모리 문제를 진단하는 데 사용할 수 있는 다른 도구가 있습니다.

이벤트에 대한 응답으로 메모리 해제

메모리 관리 개요에 설명된 대로 Android는 중요한 작업을 위한 메모리를 확보하기 위해 필요한 경우 앱에서 메모리를 회수하거나 앱을 완전히 중지할 수 있습니다. 시스템 메모리의 균형을 유지하고 시스템에서 앱 프로세스를 중지하지 않도록 하려면 ComponentCallbacks2 인터페이스를 Activity 클래스에 구현하면 됩니다. 제공된 onTrimMemory() 콜백 메서드는 앱이 자발적으로 메모리 사용량을 줄일 수 있는 좋은 기회를 제공하는 수명 주기 또는 메모리 관련 이벤트를 앱에 알립니다. 메모리를 확보하면 메모리 부족 종료에 의해 앱이 종료되는 빈도를 줄일 수 있습니다.

onTrimMemory() 구현은 TRIM_MEMORY_UI_HIDDENTRIM_MEMORY_BACKGROUND 이벤트에만 집중해야 합니다. (Android 14부터 시스템은 더 이상 다른 기존 상수에 대한 알림을 제공하지 않습니다. 이러한 상수는 Android 15에서 공식적으로 지원 중단되었습니다.)

  • TRIM_MEMORY_UI_HIDDEN: 이 신호는 앱의 UI가 사용자의 뷰에서 전환되었음을 나타냅니다. 이 전환은 비트맵, 동영상 재생 버퍼 또는 복잡한 애니메이션 리소스와 같이 UI에 엄격하게 연결된 상당한 메모리 할당을 해제할 수 있는 기회를 제공합니다.

  • TRIM_MEMORY_BACKGROUND: 이 신호는 프로세스가 백그라운드에 상주하며 이제 시스템의 전역 메모리 요구사항을 충족하기 위해 종료될 수 있음을 나타냅니다. 프로세스가 캐시된 상태로 유지되는 기간을 늘리고 앱 콜드 스타트 수를 줄이려면 사용자가 세션을 재개한 후 쉽게 재구성할 수 있는 리소스를 적극적으로 해제해야 합니다.

이 코드 샘플은 다양한 메모리 관련 이벤트에 응답하도록 onTrimMemory() 콜백을 구현하는 방법을 보여줍니다.

Kotlin

import android.content.ComponentCallbacks2
// Other import statements.

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    override fun onTrimMemory(level: Int) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

Java

import android.content.ComponentCallbacks2;
// Other import statements.

public class MainActivity extends AppCompatActivity
    implements ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    public void onTrimMemory(int level) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

필요한 메모리 용량 확인

Android에서는 여러 개의 프로세스 실행을 허용하기 위해 각 앱에 할당된 힙 크기를 엄격하게 제한합니다. 정확한 힙 크기 제한은 기기에서 전체적으로 사용할 수 있는 RAM 크기를 기준으로 기기에 따라 다릅니다. 앱이 힙 용량에 도달하여 더 많은 메모리를 할당하려고 하면 시스템에서 OutOfMemoryError가 발생합니다.

메모리 부족을 방지하려면 시스템에 쿼리하여 현재 기기에서 사용할 수 있는 힙 공간의 양을 확인하세요. `getMemoryInfo()`를 호출하여 시스템에 이 값을 쿼리할 수 있습니다. 이 메서드는 사용 가능한 메모리, 총 메모리 및 메모리 기준점(시스템에서 프로세스를 중지하기 시작하는 메모리 수준)과 같은 기기의 현재 메모리 상태 정보를 제공하는 ActivityManager.MemoryInfo 객체를 반환합니다. ActivityManager.MemoryInfo 객체는 또한 기기의 메모리가 부족한지 알려주는 간단한 부울인 lowMemory를 노출합니다.

다음 코드 스니펫 예는 앱에서 getMemoryInfo() 메서드를 사용하는 방법을 보여줍니다.

Kotlin

fun doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    if (!getAvailableMemory().lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private fun getAvailableMemory(): ActivityManager.MemoryInfo {
    val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return ActivityManager.MemoryInfo().also { memoryInfo ->
        activityManager.getMemoryInfo(memoryInfo)
    }
}

Java

public void doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();

    if (!memoryInfo.lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {
    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);
    return memoryInfo;
}

메모리 부족 종료 모니터링

시스템 메모리가 매우 부족해지면 사용자에게 표시되는 메모리 부족 종료 (LMK)가 발생합니다. 메모리가 부족하면 lmkd (메모리 부족 종료 데몬)가 oom_adj_score를 기준으로 프로세스를 종료합니다. 캐시되거나 연결된 UI가 없는 서비스 (예: 작업)를 실행하는 앱은 점수가 가장 높으며 먼저 종료됩니다. 메모리가 매우 부족한 상태로 유지되면 데몬은 oom_adj_score가 0인 프로세스에서 메모리를 회수해야 합니다. 이 점수는 표시되는 앱을 위해 예약되어 있으므로 종료 시 즉각적이고 비정상적인 프로세스 종료가 발생합니다. 최종 사용자에게는 앱이 비정상 종료된 것처럼 보이며, 표준 수명 주기 상태 저장 메커니즘을 우회하고 사용자 진행 상황이 손실되는 경우가 많습니다.

포그라운드 프로세스 종료는 메모리 관리 부실의 충실도 높은 프록시 역할을 하므로 Android Vitals에서 기본적으로 중점을 둡니다. LMK 발생률이 1% 보다 높으면 즉각적인 조치가 필요함을 나타내지만, 발생률이 낮다고 해서 반드시 상태가 양호한 것은 아닙니다. 사용자가 인식하는 LMK 발생률이 낮다는 것은 LMK 데몬이 백그라운드에 있는 동안 프로세스를 자주 종료하여 '웜 스타트' 성능과 멀티태스킹 유동성을 저하시킨다는 의미일 수 있습니다. 따라서 장기적인 안정성과 기기 상태를 보장하려면 현재 LMK 점수와 관계없이 메모리 권장사항을 준수하는 것이 좋습니다.

ProfilingManager를 사용하여 메모리 문제 추적

Android 플랫폼은 설정한 트리거를 기반으로 프로덕션에서 사용자 데이터를 캡처할 수 있는 ProfilingManager 고급 관찰 가능성 API를 제공합니다. 이렇게 하면 재현하기 어려운 메모리 문제를 식별하는 데 도움이 될 수 있습니다.

Android 17에서 도입된 두 가지 새로운 트리거는 메모리 문제를 발견하는 데 특히 유용합니다.

ProfilingManager를 사용하여 프로그래매틱 방식으로 트리거를 등록 하고 검색하는 방법에 관한 자세한 내용은 트리거 기반 프로파일링 문서를 참고하세요.

앱 기반 프로파일링을 사용하여 시작 및 종료 트레이스 지점을 수동으로 정의할 수도 있습니다. 메모리 누수 또는 과도한 메모리 사용이 의심되는 영역에서 힙 덤프 또는 힙 프로필을 수동으로 캡처하는 것이 좋습니다.

메모리 효율성이 높은 코드 구성 사용

일부 Android 기능, Java 클래스, 코드 구성은 다른 기능, 클래스, 구성에 비해 메모리를 더 많이 사용합니다. 코드에서 효율성이 높은 대안을 선택하면 앱에서 사용하는 메모리의 양을 최소화할 수 있습니다.

서비스를 드물게 사용

불필요하면 서비스를 실행 상태로 두지 않는 것이 좋습니다. 불필요한 서비스를 계속 실행 상태로 두는 것은 Android 앱에서 일으킬 수 있는 최악의 메모리 관리 실수 중 하나입니다. 앱이 백그라운드에서 작동하는 서비스가 필요한 경우 작업을 실행해야 하는 경우가 아니면 서비스를 실행 상태로 두지 마세요. 작업이 완료되면 서비스를 중지합니다. 그러지 않으면 메모리 누수가 발생할 수 있습니다.

서비스를 시작하면 시스템에서는 그 서비스의 프로세스를 실행 상태로 유지하려고 합니다. 이 동작으로 인해 서비스에서 사용하는 RAM을 다른 프로세스에서 사용할 수 없기 때문에 서비스 프로세스의 비용이 매우 높아집니다. 이로 인해 시스템에서 LRU 캐시에 유지할 수 있는 캐시된 프로세스의 수가 줄어들어 앱 전환의 효율성이 저하됩니다. 심지어 메모리가 부족하고 시스템에서 현재 실행 중인 모든 서비스를 호스팅하기에 충분한 프로세스를 유지할 수 없게 되면 시스템에서 스래싱이 발생할 수 있습니다.

일반적으로 지속적인 서비스 사용은 사용 가능한 메모리를 끊임없이 요구하므로 피하는 것이 좋습니다. 대신 대체 구현(예: WorkManager)을 사용하는 것이 좋습니다. WorkManager를 사용하여 백그라운드 프로세스를 예약하는 방법에 관한 자세한 내용은 지속적인 작업을 참고하세요.

최적화된 데이터 컨테이너 사용

프로그래밍 언어에서 제공하는 일부 클래스는 휴대기기에서 사용하도록 최적화되지 않았습니다. 예를 들어, 일반 HashMap 구현은 모든 매핑에 별도의 항목 객체가 필요하므로 메모리 사용이 비효율적일 수 있습니다.

Android 프레임워크에는 SparseArray, SparseBooleanArray, and LongSparseArray를 비롯하여 여러 최적화된 데이터 컨테이너가 포함되어 있습니다. 예를 들어, SparseArray 클래스는 키와 때로는 값(항목당 한두 개의 객체 생성)을 시스템에서 오토박싱하지 않으므로 더 효율적입니다.

필요한 경우 언제든지 가벼운 데이터 구조를 위해 원시 배열로 전환할 수 있습니다.

코드 추상화 관련 주의사항

개발자는 코드 유연성과 유지관리를 개선할 수 있어 추상화를 좋은 프로그래밍 관행으로 사용하는 경우가 많습니다. 그러나 추상화에는 일반적으로 더 많은 코드가 실행되어야 합니다. 앱의 코드 및 리소스 공간 줄이기에 자세히 설명된 대로 컴파일된 코드베이스가 클수록 앱에 필요한 실제 RAM이 직접적으로 증가합니다. 추상화가 크게 유용하지 않다면 사용하지 마세요.

직렬화된 데이터에 라이트 protobuf 사용

프로토콜 버퍼 (protobuf)는 Google에서 구조화된 데이터 직렬화를 위해 설계한 언어 및 플랫폼 중립적인 확장 가능한 메커니즘으로, XML과 비슷하지만 더 작고 빠르며 단순합니다. 데이터에 protobuf를 사용하는 경우 항상 클라이언트 측 코드에서 라이트 protobuf를 사용하세요. 일반 protobuf는 지나치게 상세한 코드를 생성하므로 RAM에서 앱의 코드 공간을 늘리고 (앱의 코드 및 리소스 공간 줄이기 참고) APK 크기 증가에 기여합니다.

자세한 내용은 protobuf 리드미를 참고하세요.

메모리 누수 관련 주의사항

잘못된 참조 관리로 인해 객체가 유용한 수명보다 오래 지속되는 메모리 누수가 발생하여 가비지 컬렉터가 누수된 객체의 메모리를 회수하지 못할 수 있습니다. 메모리 누수를 방지하려면 수명 주기 인식 디자인을 구현하세요.

메모리 급변 방지

가비지 컬렉션 이벤트는 앱 성능에 영향을 주지 않습니다. 하지만 단기간에 많은 가비지 컬렉션 이벤트가 발생하면 가비지 컬렉터와 앱 스레드 사이에 필요한 상호작용으로 인해 배터리가 빠르게 소모되고 프레임을 설정하는 데 걸리는 시간이 미미하게나마 늘어날 수 있습니다. 시스템에서 가비지 컬렉션에 소비하는 시간이 길어질수록 배터리가 빠르게 소모됩니다.

종종 메모리 급변 으로 인해 수많은 가비지 컬렉션 이벤트가 발생할 수 있습니다. 실제로 메모리 급변은 특정 기간 내에 발생하는 할당된 임시 객체의 수를 나타냅니다.

예를 들어, for 루프 내에 여러 임시 객체를 할당할 수 있습니다. 또는 뷰의 onDraw() 함수 내에서 새 Paint 또는 Bitmap 객체를 만들 수 있습니다. 두 경우 모두 앱에서 많은 객체를 빠르게 대량으로 만듭니다. 이로 인해 새로운 객체 영역에서 사용 가능한 모든 메모리가 빠르게 소모되어 가비지 컬렉션 이벤트를 발생시킬 수 있습니다.

문제를 해결하기 전에 메모리 프로파일러를 사용하여 코드에서 메모리 급변이 높은 위치를 찾으세요.

코드에서 문제 영역을 확인한 후에는 성능이 중요한 영역 내에 할당 수를 줄여 보세요. 또한 내부 루프에서 객체를 이동하거나 factory 기반 할당 구조로 객체를 이동하는 것이 좋습니다.

객체 풀이 사용 사례에 도움이 되는지 평가할 수도 있습니다. 객체 풀을 사용하면 더 이상 필요하지 않은 객체 인스턴스를 삭제하는 대신 풀로 해제합니다. 다음번에 이 유형의 객체 인스턴스가 필요할 때 이를 할당하는 대신 풀에서 가져올 수 있습니다.

성능을 철저히 평가하여 특정 상황에서 객체 풀이 적합한지 확인합니다. 객체 풀을 사용함으로써 성능이 더 악화되는 경우도 있습니다. 풀을 사용하면 할당이 방지되지만 그 밖의 오버헤드가 발생합니다. 예를 들어, 풀을 유지관리하려면 보통 동기화가 진행되는데, 이 과정에서 무시할 수 없는 오버헤드가 발생합니다. 또한 해제 중에 메모리 누수를 방지하기 위해 풀링된 객체 인스턴스를 지운 다음 획득 중에 인스턴스를 초기화하는 과정에서도 0이 아닌 오버헤드가 발생할 수 있습니다.

풀에 필요한 것보다 많은 객체 인스턴스를 보유하는 것도 가비지 컬렉션에 부담이 됩니다. 객체 풀은 가비지 컬렉션 호출 수를 줄이지만 라이브 (연결 가능한) 바이트 수에 비례하므로 모든 호출에 필요한 작업량은 증가하게 됩니다.