AI 사용기
AI 활용기: du가 41G라던 폴더를 지웠더니 13G만 비었다
맥 디스크 정리 자동화 스크립트를 AI와 짜다가, APFS 클론 때문에 du 용량과 실제 회수량이 최대 3배 어긋난다는 걸 알게 된 사례와, 같은 문제를 다루는 오픈소스 도구를 같이 정리했다.
AI에게 디스크 정리 스크립트를 맡기는 사람에게, du가 보여주는 숫자와 삭제 후 실제로 비는 용량이 왜 다를 수 있는지 구체적 사례로 보여준다.
크롬 프로필 클론 폴더가 du 기준 41G였는데 지우고 나니 df 기준으로는 13G만 회수됐다 — 시뮬레이터 런타임도 71G가 49G로 어긋났다. macOS APFS는 clonefile(2)로 만든 폴더가 원본과 디스크 블록을 공유하기 때문에, du는 파일마다 논리 크기를 더해 보여줄 뿐 실제로 물리 블록을 얼마나 공유하는지는 계산하지 않는다. 실제 회수량의 유일한 정답은 df가 보여주는 블록 수뿐이고, 이 어긋남은 macOS 개인 스크립트만의 문제가 아니라 pnpm·uv·git-worktree처럼 clonefile을 쓰는 도구 전반에서 반복돼 이를 겨냥한 전용 분석 도구(duh)까지 나와 있다.
AI가 짜준 디스크 정리 스크립트가 du 숫자만으로 '몇 GB 확보'라고 보고하면 그 수치를 그대로 믿지 말고, 삭제 전후 df 스냅샷을 직접 비교해 실제 회수량을 확인한다.
먼저 답하면
맥 내장 디스크가 27GiB밖에 안 남아서 AI와 함께 정리 스크립트를 짰다. du로 큰 폴더부터 찾아 지우는 뻔한 접근이었는데, 크롬 프로필 클론 폴더 하나를 지우고 df로 다시 재보니 du가 말한 41GiB가 아니라 13GiB만 비어 있었다. iOS 시뮬레이터 런타임도 71GiB짜리를 지웠는데 49GiB만 회수됐다. 원인은 macOS APFS의 클론 파일(clonefile) 구조였다.
실제 겪은 일
디스크 정리 프로젝트를 새로 만들면서 가장 먼저 bin/disk-survey.sh로 큰 항목을 찾았다. du -sh로 정렬해 상위 폴더를 뽑고, 위에서부터 지워가며 여유 공간을 늘리는 계획이었다. 크롬의 프로필 클론 폴더가 du 기준 41GiB로 1위였다. 지우고 df로 재니 실제로 비어난 공간은 13GiB뿐이었다. 이어서 iOS 시뮬레이터 런타임 폴더(du 71GiB)를 지웠을 때도 49GiB만 회수됐다. 두 번 다 du가 알려준 숫자와 실제 회수량이 최대 3배 가까이 벌어졌다.
원인을 확인해보니 macOS의 APFS 파일시스템은 clonefile(2) 시스템 콜로 폴더나 파일을 복제할 때 실제 데이터를 복사하지 않는다. 새 inode를 만들어 원본과 같은 디스크 블록을 가리키게 할 뿐이고, 이후 한쪽이 실제로 수정된 블록만 그때 가서 별도로 저장한다(copy-on-write). 크롬이 프로필을 “복제”할 때, 그리고 Xcode가 시뮬레이터 런타임을 파생시킬 때 바로 이 메커니즘을 쓴다. du는 파일마다 논리 크기를 그대로 더해서 보여주므로, 클론된 폴더는 실제로 차지하는 디스크 블록과 무관하게 원본과 똑같은 크기로 두 번, 세 번 잡힌다. 반대로 df는 볼륨의 실제 할당 블록 수만 보여주기 때문에, 클론된 폴더 하나를 지워도 다른 클론이 여전히 같은 블록을 쓰고 있으면 그만큼만 회수되고 나머지는 비지 않는다.
이후 정리 스크립트의 규칙을 바꿨다. du 숫자는 “삭제 후보를 찾는 용도”로만 쓰고, 실제 회수량은 항목을 하나 지운 뒤 df /System/Volumes/Data로 전후 차이를 재는 방식으로 확인하게 했다. du ≠ APFS 회수량이라는 전제를 정리 프로젝트 문서에 가장 비싼 함정으로 남겨뒀다.
온라인에 있는 비슷한 사례
이 문제는 개인 스크립트만의 특이 케이스가 아니었다. GitHub에 공개된 duh라는 도구는 정확히 이 문제를 풀기 위해 만들어졌다. 설명에 따르면 du나 다른 GUI 용량 분석기는 파일별 크기를 단순히 더하는데, clonefile(2)로 만들어지고 pnpm·uv·PostgreSQL·git-worktree 같은 도구가 실제로 쓰는 APFS 클론은 매 클론마다 전체 크기를 보고하면서도 물리 블록은 공유한다. 그래서 클론이 많은 디렉터리 트리는 실제 디스크 비용을 10~100배까지 과대평가할 수 있다고 설명한다. duh는 APFS 클론 ID로 클론 가족을, inode로 하드링크 가족을 찾아내 “지우면 실제로 얼마나 비는지”를 계산하는 방식으로 이 문제에 대응한다.
같은 현상은 macOS에 국한되지 않는다. IBM 기술지원 문서도 df와 du가 서로 다른 값을 보고하는 원인들을 정리하면서, 파일시스템이 공유·중복제거 구조를 쓸 때 du의 논리 합산과 df의 실제 블록 할당이 어긋날 수 있다고 설명한다. Apple 커뮤니티의 APFS copy-on-write 스레드에서도 여러 사용자가 같은 혼란을 보고한다 — HFS+에서는 복사가 곧 새 블록 소비였지만 APFS에서는 아니라는 점이 이 함정의 근본 원인으로 지목된다.
결론
AI가 짜준 정리 스크립트가 “이 폴더를 지우면 41GB를 확보합니다”라고 자신 있게 말해도, 그 숫자의 출처가 du라면 APFS 위에서는 액면 그대로 믿을 수 없다. duh 같은 전용 도구가 따로 나올 만큼 이건 macOS 사용자 전반이 반복해서 부딪히는 함정이다. 실제 회수량을 확인하는 유일한 방법은 결국 df로 전후를 직접 재는 것이고, 디스크가 꽉 찬 상태에서 대량 삭제·이동을 자동화할 때는 이 검증 없이 “몇 GB 확보했다”는 로그만 믿고 다음 단계로 넘어가지 않는 게 맞다.