del 했는데 메모리가 안 줄어들 때: RSS와 tracemalloc이 다른 이유

del 했는데 메모리가 줄어들지 않는 이유는 간단합니다. del이 지우는 건 변수와 객체 사이의 참조 하나일 뿐, 객체가 차지한 메모리 블록 자체가 아니기 때문입니다. 게다가 그 블록이 실제로 해제되더라도 운영체제에 돌려주는 건 또 다른 단계라서, tracemalloc이 보여주는 수치와 OS가 보고하는 RSS(Resident Set Size)가 서로 다르게 움직입니다. 이 글은 CPython(표준 파이썬 구현체), 리눅스 + glibc 환경을 기준으로 … Read more

float64를 float32로 낮춰도 되나 — 오차는 여기서 드러납니다

float64를 float32로 낮추면 정밀도가 정확히 절반으로 줄어든다고 생각하기 쉽지만, 실제로는 비트 수가 줄면서 생기는 반올림 오차가 특정 지점에서만 두드러지게 나타납니다. 결과부터 말하자면, 값의 크기가 커지거나 같은 연산을 수없이 반복해 오차가 누적되는 구간에서만 문제가 생기고, 평범한 연산 대부분에서는 체감되지 않습니다. float64를 float32로 낮춰도 되나 고민하고 계시다면, 아래 몇 가지 지점만 확인하면 판단이 쉬워집니다. float32와 float64, 비트 … Read more

numpy 브로드캐스팅에서 메모리가 터지는 거리 행렬, 쪼개서 계산하는 법

결론부터 말씀드리면, 거리 행렬을 구할 때 X[:, None, :] – X[None, :, :] 식으로 한 번에 브로드캐스팅하면 (N, N, D) 크기의 중간 배열이 그대로 메모리에 올라가서 터집니다. 해결책은 ① 제곱합 전개(내적 트릭)로 중간 배열 자체를 없애거나, ② 행 단위로 쪼개서 필요한 블록만 메모리에 올리는 것입니다. 데이터가 커질수록 numpy 브로드캐스팅에서 메모리가 터지는 지점은 거의 항상 이 … Read more

pandas 대신 DuckDB를 쓸 시점, 조인·집계·메모리 기준으로 정리

결론부터 말씀드리면, pandas 대신 DuckDB를 쓸 시점은 데이터 크기가 아니라 작업의 종류로 판단하는 게 정확합니다. 단일 파일을 훑어보는 수준이라면 pandas로 충분하지만, 여러 테이블을 조인하거나 그룹 집계를 반복하는 순간, 혹은 데이터가 메모리 용량에 슬슬 닿기 시작하는 시점부터는 DuckDB 쪽이 코드도 짧아지고 처리도 안정적입니다. 이 글에서는 조인, 집계, 메모리라는 세 기준으로 전환 시점을 구체적인 코드와 함께 짚어보겠습니다. … Read more

메모리보다 큰 파일을 Polars로 다루는 법: Lazy와 Streaming이 갈리는 지점

결론부터 말씀드리면, 메모리보다 큰 파일을 Polars로 처리할 때 실제 관건은 lazy API가 아니라 streaming 실행 여부입니다. scan_csv나 scan_parquet로 파일을 lazy하게 열어도 collect()를 그냥 호출하면 결과를 통째로 메모리에 쌓아버려서 똑같이 메모리 부족이 납니다. 이 글은 Polars의 lazy 평가와 streaming 엔진이 정확히 어느 지점에서 갈라지는지, 그리고 어떤 코드를 써야 메모리 사용량이 실제로 줄어드는지를 다룹니다. 아래 내용은 파이썬용 … Read more

문자열 컬럼이 메모리 절반을 먹을 때: object·category·Arrow 비교

판다스(pandas)로 큰 CSV나 DB 테이블을 읽었을 때, 왜 유독 문자열 컬럼이 메모리 절반을 차지해 버리는 걸까요? 정수나 실수 컬럼은 고정 크기 배열로 저장되지만, 기본 object dtype 문자열 컬럼은 셀 하나마다 별도의 파이썬 문자열 객체를 만들고 그 주소를 포인터 배열로 연결하기 때문입니다. 이 글에서는 pandas 2.x와 pyarrow 환경을 기준으로 object, category, Arrow 기반 문자열(string[pyarrow] / pd.ArrowDtype) … Read more

df.apply가 for문보다 느릴 때, 벡터화 4단계로 뜯어봅니다

이 글에서는 df.apply가 for문보다 느릴 때 실제로 어떤 단계를 거쳐야 속도가 빨라지는지, pandas 1.x~2.x 기준 코드와 실측 비교표로 확인합니다. 핵심 답부터 말씀드리면, 느린 원인은 ‘apply를 썼다’는 사실 자체가 아니라 행 하나마다 파이썬 함수를 호출하는 구조에 있습니다. 같은 계산을 pandas Series 연산이나 numpy 배열 연산으로 바꾸는 순간, 반복 호출 자체가 사라지면서 속도 차이가 크게 벌어집니다. df.apply가 … Read more

pandas 3.0에서 조용히 깨지는 코드 — Copy-on-Write가 바뀐 뒤 생기는 일

결론부터 말씀드리면, pandas 3.0에서 조용히 깨지는 코드 대부분은 “체인 할당(chained assignment)” 패턴입니다. df[mask][“col”] = value처럼 한 줄로 쓰면 이제 바로 에러가 나서 오히려 고치기 쉽지만, 임시 변수에 담아 두 줄로 나눠 쓴 코드는 에러도 경고도 없이 그냥 원본을 바꾸지 못한 채 넘어갑니다. pandas 3.0은 이전까지 옵션으로 켜고 끌 수 있던 Copy-on-Write(CoW)를 기본이자 유일한 동작 방식으로 … Read more

컨텍스트를 길게 넣을수록 답이 나빠지는 이유와 위치 효과

많은 분들이 컨텍스트 창이 넉넉하면 자료를 한 번에 다 밀어 넣는 편이 무조건 유리하다고 생각합니다. 하지만 실제로는 컨텍스트를 길게 넣을수록 답이 나빠지는 경우가 자주 생깁니다. 모델이 실제로 활용하는 ‘실효 길이’는 공식 스펙보다 훨씬 짧고, 특히 프롬프트 중간에 놓인 정보는 앞뒤보다 자주 무시됩니다. 그래서 토큰을 얼마나 채우느냐보다 어디에 배치하느냐가 답변 품질을 좌우합니다. 컨텍스트 창이 커도 실효 … Read more

쓰던 LLM 프로바이더가 멈췄을 때, 다른 모델로 넘기며 깨지는 것들

결론부터 말씀드리면, 쓰던 LLM 프로바이더가 멈췄을 때 단순히 모델 이름만 바꿔서 다른 프로바이더로 넘기면 열에 아홉은 어딘가에서 예외가 터집니다. API 응답 형식 자체가 프로바이더마다 다르게 설계돼 있기 때문입니다. 이 글에서는 OpenAI Chat Completions API와 Anthropic Messages API를 기준으로, 실제로 어느 지점에서 코드가 깨지는지와 그걸 최소한으로 흡수하는 방법을 정리했습니다. 프로바이더 장애 때 넘어가는 순서와 가장 먼저 … Read more