안드로이드/꺼진개념다시보기

[Android] Serializable, Parcelable

sxunea 2024. 7. 7. 23:55

 

Serializable

 

Serializable, 즉 직렬화는 객체 또는 데이터를 연속적인 데이터 (byte-stream) 형태로 변환하는 작업이다. 역직렬화는 그 이름처럼 바이트 스트림 형태를 다시 원본 객체로 변환하는 작업을 의미한다.

 

그렇다면 직렬화는 어디에 필요할까 ?

 

 

IPC

 

분명 어디서 들어본 용어이다. 컴퓨터공학 전공자라면 맞다. 학부 운영체제 수업에 등장하는 개념으로 각각의 프로세스는 별도의 메모리를 갖기 때문에 프로세스 간 데이터 공유를 위해서는 별도의 기법이 필요한데, 이때 등장하는 기법이 IPC(Inter Process Communication)이다. 운영 체제는 프로세스가 서로 독립적으로 실행되도록 설계되어 있기 때문에, 하나의 프로세스가 다른 프로세스의 메모리에 직접 접근하는 것은 불가능하므로 이 기법을 사용한다.

 

이때 플랫폼 별로 상이하긴 하지만, 직렬화를 사용하면 기존 데이터 객체를 모두 byte stream 이라는 표준 형식으로 변환하면 사용하기가 용이하다. 예를 들어 안드로이드에서는 프로세스간 통신을 위해 Binder를 사용할 수 있는데, 이때 다른 프로세스에 byte-stream을 전달할 수 있으며, 이러한 byte-stream을 만들기 위해 직렬화가 쓰인다

 

 

 

java.io.Serializable

 

 

Serializable은 자바에서 제공하는 표준 인터페이스로, 객체를 바이트 스트림으로 변환하여 저장하거나 전송할 수 있게 해준다. 하지만 Serializable 인터페이스를 사용하는 데에는 몇 가지 성능 문제와 비용이 따른다.

 

 

 

Serializable의 동작 방식

Serializable 인터페이스는 '마커 인터페이스(Marker Interface)'로, 어떤 메서드도 제공하지 않고, 클래스가 직렬화 대상임을 나타내기만 한다. 자바의 기본 직렬화 메커니즘은 JVM에서 자동으로 직렬화 및 역직렬화할 수 시켜주고, 이 과정에서 자바는 내부적으로 Reflection을 사용하여 객체의 필드와 메타데이터를 분석한다.

 

 

 

Reflection과 성능 문제

JVM은 클래스 정보를 클래스 로더를 통해 읽어와서 해당 정보를 JVM 메모리에 저장한다. 이때 저장된 클래스에 대한 정보를 Reflection이라고 하고, 따라서 Reflection은 런타임에 객체의 메타데이터를 조사하고 조작할 수 있게 해주는 강력한 도구이다. 하지만 다음과 같은 단점을 가지기도 한다. 

 

  1. 추가 객체 생성: 직렬화 과정에서 객체의 메타데이터와 필드를 조사하기 위해 많은 추가 객체가 생성된다. 이러한 객체는 메모리를 차지하고, 가비지 컬렉터의 대상이 된다.
  2. 런타임 오버헤드: Reflection은 런타임에 동작하므로, 컴파일 타임에 검증되고 최적화된 코드에 비해 속도가 느리다
  3. 가비지 컬렉터(Garbage Collector) 부하 증가: Reflection을 통해 생성된 많은 임시 객체는 가비지 컬렉터의 대상이 된다. 이는 가비지 컬렉터가 더 자주, 더 오래 동작하게 하여 CPU 사용량 증가와 배터리 소모를 초래할 수 있다

 

 

추가적으로, Serializable 인터페이스를 구현하는 모든 객체는 고유의 식별번호 (SUID)를 부여 받는다. 이때 SUID가 필수는 아니지만 동일 객체인지를 판별하고 안전한 직렬화, 역직렬화를 하기 위해서는 명시하는 것이 좋다. 하지만 직렬화할 객체에 새로운 필드가 추가되는 것이 아닌 타입이 변경될 경우에도 예외 (InvalidClassException)는 발생하게 되어 안전하지 않다는 단점 또한 존재한다. 

 

그래서 이러한 단점으로 Parcelable이 등장했다. 

 

 

Parcelable

  • 마찬가지로 직렬화를 위한 인터페이스이다
  • Serializable과 다르게 표준 Java가 아닌 Android SDK의 인터페이스이다
  • Serializable과 다르게 reflection을 사용하지 않고, 사용자가 처리 방법을 명시적으로 작성한다
  • IPC(Inter Process Communication)에 최적화된 기능을 제공한다

앞서말했듯이 serializable은 필수 메서드를 포함하고 자동으로 처리되지만, parcelable은 마커 인터페이스가 아니기때문에 구현해야 하는 필수 메서드를 포함한다는 단점이 존재하기는 한다. 

 

 

추가적으로, parcelable의 장점에 대해 검색해보면 serializable 보다 빠르다는 내용이 많다. 이에 대해서는 하단의 참고 블로그를 읽어보고 개발자의 성향과 요구사항과 프로젝트의 상황에 맞춰 판단하는 것이 좋을 것 같다는 생각이든다. 

 

 

@Parcelize

마지막으로 요놈이다. 안드로이드에서 제공하는 annotation으로, kotlin-parcelize 플러그인을 추가함으로서 parcelable의 구현을 자동으로 해준다. 따라서 필수 메서드를 작성해야해 보일러 플레이트 코드가 증가할 수 있다는 parcelable의 단점까지 모두 커버한다. 

 

 

 

 

참고자료

 

Parcelable vs Serializable , 정말 Serializable은 느릴까?

원문 : “Parcelable vs Serializable”

medium.com

 

 

(Android) 직렬화와 역직렬화

Serializable, Parcelable 선택 기준

medium.com