메모리 누수의 원인 10가지

2023. 12. 15. 13:53개발/Android

1. Non-Static Inner Classes

  • Kotlin의 내부 클래스는 외부 클래스에 대한 암시적 참조를 보유할 수 있음
Example:
class MyActivity : AppCompatActivity() {
     private inner class MyThread : Thread() {
         override fun run() {
             // Task
         }
     }
}
  • 해결 방법: 내부 클래스를 정적으로 만들거나, 별도의 클래스를 사용하기. 필요한 경우 외부 클래스에 대한 약한 참조를 전달

2. Handlers and Runnables

  • 핸들러가 외부 클래스에 대한 참조를 보유하는 경우 메모리 누수가 발생할 수 있음
Example:
class MyActivity : AppCompatActivity() {
     private val handler = Handler(Looper.getMainLooper())
     private val runnable = Runnable { /* Task */ }
     override fun onDestroy() {
         super.onDestroy()
         handler.removeCallbacks(runnable)
     }
}
  • 해결 방법: onDestroy메서드에서 콜백을 모두 제거

3. Anonymous Listeners

  • 리스너가 실수로 Activity나 View에 대한 참조를 보유할 수 있음
Example:
class MyActivity : AppCompatActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         findViewById<Button>(R.id.myButton).setOnClickListener {
             // Click action
         }
     }
}
  • 해결방법: onDestroy 메소드에서 리스너를 지우거나 정적 클래스를 사용

4. Static Views or Contexts

  • 정적 뷰 또는 컨텍스트 참조는 메모리 누수로 이어질 수 있음
Example:
class MyActivity : AppCompatActivity() {
     companion object {
         private var staticView: View? = null
     }
     override fun onCreate(savedInstanceState: Bundle?) {
         staticView = findViewById(R.id.myView)
     }
}
  • 해결 방법: 뷰나 컨텍스트에 대한 정적 참조를 피하고, 필요한 경우 약한 참조를 사용

5. Improper LiveData Observations

  • 수명주기를 고려하지 않고 LiveData를 관찰함
Example:
class MyActivity : AppCompatActivity() {
     private val viewModel: MyViewModel by viewModels()
      override fun onCreate(savedInstanceState: Bundle?) {
         viewModel.myLiveData.observe(this, { data ->
             /* Update UI */
          })
     }
}
  • 해결 방법: viewLifecycleOwnerFragments와 같은 수명 주기 인식 구성 요소를 사용하여 LiveData를 관찰

6. Singleton with Context

  • 컨텍스트에 대한 참조를 보유하는 싱글톤은 누출을 일으킬 수 있음
Example:
object MySingleton {
     var context: Context? = null
}
  • 해결 방법: Activity나 View컨텍스트 대신, 애플리케이션 컨텍스트를 싱글톤에 전달

7. Bitmaps

  • 대형 비트맵을 제대로 관리하지 않으면 많은 메모리를 소비할 수 있음
Example:
class MyActivity : AppCompatActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         val bitmap = BitmapFactory.decodeResource(resources, R.drawable.large_image)
         // Use bitmap
     }
}
  • 해결방법: 비트맵을 신중하게 사용하고 recycle()완료되면 호출. Glide나 Picasso와 같은 이미지 로딩 라이브러리를 사용

8. WebViews

  • WebView는 컨텍스트에 대한 참조를 보유할 수 있음
Example:
class MyActivity : AppCompatActivity() {
     private lateinit var webView: WebView
     override fun onCreate(savedInstanceState: Bundle?) {
         webView = findViewById(R.id.myWebView)
         // Set up WebView
     }
}
  • 해결 방법: onDestroy 메소드에서 WebView를 지우고, 가능한 경우 애플리케이션 컨텍스트를 사용

9. Broadcast Receivers

  • broadcast receivers등록을 취소하지 않으면 누출이 발생할 수 있음
Example:
class MyActivity : AppCompatActivity() {
     private val receiver = MyReceiver()
      override fun onStart() {
         registerReceiver(receiver, IntentFilter("SOME_ACTION"))
     }
     override fun onStop() {
         unregisterReceiver(receiver)
         super.onStop()
     }
}
  • 해결 방법: 항상 해당 수명 주기 메서드에서 등록을 취소하기

10. Event Listeners in RecyclerView Adapters

  • RecyclerView 어댑터의 이벤트 리스너는 Activity 또는 Fragment에 대한 참조를 보유할 수 있음
Example:
class MyAdapter(private val items: List<Item>, private val activity: AppCompatActivity) : RecyclerView.Adapter<MyViewHolder>() {
     // Adapter implementation
}
  • 해결 방법: 콜백에 인터페이스나 람다 함수를 사용하고, Activity나 Fragment 컨텍스트를 어댑터에 전달하지 않기.


Uploaded by N2T

'개발 > Android' 카테고리의 다른 글

Android의 모듈식 접근 방식  (0) 2023.12.15
MenuProvider  (0) 2023.12.15
Android 에서 TDD를 습관화하기  (0) 2023.11.30
Useful modifier  (0) 2023.11.30
Compose Viewpager  (1) 2023.11.01