[TIL] 메모리 관리
A. 금일 학습내용
1. 메모리란 무엇인가
프로젝트를 하면서 가장 많이 본 에러문구는 Out Of Memory(OOM) 이다. 긴 시간 셀을 실행시켜 나온 메모리에러를 볼 때마다 절망적이었다. 그러나 빅데이터를 다루는 사람이라면 메모리 관리도 하나의 능력이다.
1) 메모리의 정의
'메모리(Memory) = 기억장치' 이다. 크게 RAM 과 Disk(SSD)로 나눌 수 있고, Disk(SSD)는 우리가 익히 잘 아는 저장공간을 의미한다. 장기적으로 데이터를 보관하는 공간으로 전원이 꺼져도 데이터는 사라지지 않는다.
2) RAM의 정의
'Random Access Memory' 로 사용자가 자유롭게 읽고 쓰고 지울 수 있는 기억장치를 의미한다. '주 기억장치'로 분류되며, '책상', '도마' 등으로 비유된다. 램이 많으면 한 번에 많은 일을 할 수 있으며, 이는 책상이 넓으면 그 위에 여러가지 물품을 올려놓을 수 있고, 그 물품을 다시 회수하면 물품이 있었다는 기록은 사라지기 때문이다.
램은 성능이 좋을수록, 용량이 클수록 더 많은 일을 빠르게 수행할 수 있기 때문에 다다익램이라고도 한다.
2. 데이터가 메모리에 저장되는 방법
메모리에는 수 많은 비트(0 혹은 1)가 저장되고 각각의 비트는 고유한 식별자(Unique identifier)를 통해 위치를 사용할 수 있다.
1) 정수(Integers)
컴퓨터에서는 이진법으로 표현하며, 얼마나 많은 메모리를 할당할 것인지를 말한다. 더 많은 메모리를 할당할 수록, 더 큰 숫자를 담을 수 있다.
- int8:-128 ~ 127
- int16: -32768 ~ 32727
- Int32: -2,147,483,648 ~ 2,147,483,647
- Int64: -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
부호를 위해 메모리의 단위(1비트)를 사용하지만, 담을 수 있는 숫자를 표현하자면 위와 같다.
- 오버플로(Overflow) : 크기에 맞지 않는 데이터를 넣어 의도하지 않은 결과가 나오는 것
파이썬의 데이터타입은 기본적으로 동적(Dynamic)하기 때문에 자동으로 데이터 형이 바뀐다. 이에 큰 숫자를 다루는 것에 큰 주의를 기울여야한다.
아래와 같이 메모리 데이터 타입을 지정하는 방법이 있다.
int32_cols = ["review_likes"]
int8_cols = ["review_rating"]
cate_cols = ["app_name", "author_app_version"]
memory_usage_before = df.memory_usage().sum()
df.info()
for col in int32_cols:
assert abs(df[col].max()) < 2_147_483_647
df[col] = df[col].astype(pd.Int32Dtype())
df.info()
for col in int8_cols:
assert abs(df[col].max()) < 127
df[col] = df[col].astype(pd.Int8Dtype())
df.info()
for col in cate_cols:
assert df[col].nunique() < 10_000
df[col] = df[col].astype("category")
df.info()
memory_usage_after = df.memory_usage().sum()
reduction_ratio = 1 - (memory_usage_after / memory_usage_before)
print(f"Memory Usage: {memory_usage_before:,} -> {memory_usage_after:,} ({reduction_ratio*100:.2f}% reduced)")
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 28154385 entries, 0 to 28154384
Data columns (total 8 columns):
# Column Dtype
--- ------ -----
0 review_id object
1 app_name object
2 author_name object
3 pseudo_author_id object
4 author_app_version object
5 review_rating float64
6 review_likes int64
7 review_timestamp object
dtypes: float64(1), int64(1), object(6)
memory usage: 1.7+ GB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 28154385 entries, 0 to 28154384
Data columns (total 8 columns):
# Column Dtype
--- ------ -----
0 review_id object
1 app_name object
2 author_name object
3 pseudo_author_id object
4 author_app_version object
5 review_rating float64
6 review_likes Int32
7 review_timestamp object
dtypes: Int32(1), float64(1), object(6)
memory usage: 1.6+ GB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 28154385 entries, 0 to 28154384
Data columns (total 8 columns):
# Column Dtype
--- ------ -----
0 review_id object
1 app_name object
2 author_name object
3 pseudo_author_id object
4 author_app_version object
5 review_rating Int8
6 review_likes Int32
7 review_timestamp object
dtypes: Int32(1), Int8(1), object(6)
memory usage: 1.4+ GB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 28154385 entries, 0 to 28154384
Data columns (total 8 columns):
# Column Dtype
--- ------ -----
0 review_id object
1 app_name category
2 author_name object
3 pseudo_author_id object
4 author_app_version category
5 review_rating Int8
6 review_likes Int32
7 review_timestamp object
dtypes: Int32(1), Int8(1), category(2), object(4)
memory usage: 1.1+ GB
Memory Usage: 1,801,880,772 -> 1,182,813,738 (34.36% reduced)
데이터에 맞는 데이터 타입을 부여하였을 때 30%가 넘는 메모리 감소를 확인할 수 있다.
2) 그 외 타입
정수가 아닌 타입으로는 문자열(String, Category), Datetime 등의 데이터 타입이 존재한다. 이는 정수와 마찬가지로 알맞은 메모리를 할당을 통해 메모리 최적화를 유지할 수 있다.
B. 마무리
데이터를 다룰 때는 반드시 메모리 최적화를 생각해야겠다. 시간도, 비용도 절감할 수 있는 좋은 방법이 있는데 그걸 하지 아니할 이유가 어디 있겠는가.