← All reports

IsoSubspaces share a single default aligned-memory allocator

Component: JavaScriptCore Heap | fe81aba

JSC의 GC heap은 Subspace 단위로 나뉘어 있습니다. 각 subspace에는 특정 객체 종류에 해당하는, 크기가 동일한 cell만 들어갑니다. JSFinalObject 계열이나 butterfly, JSString 같은 것들이 여기에 해당합니다. 그리고 subspace마다 16KB짜리 MarkedBlock을 묶은 BlockDirectory를 관리하는데, 이 block들은 각각 독립적으로 할당되고 sweep되며 해제됩니다.

이 commit은 subspace마다 두고 있던 기본값 하나를 제거했습니다. 자체 AlignedMemoryAllocator를 지정하지 않는 IsoSubspace는 더 이상 전용 FastMallocAlignedMemoryAllocator를 생성하지 않습니다. 대신 Heap이 소유한 단일 allocator(heap.fastMallocAllocator)를 사용하도록 변경되었습니다. custom allocator를 직접 전달하는 subspace는 영향을 받지 않습니다. 이제 기본 allocator를 공유하는 subspace들은 동일한 block pool에서 메모리를 가져오게 되는데, 그래서 BlockDirectory::findEmptyBlockToSteal()이 새 메모리를 요청하는 대신 같은 allocator를 쓰는 다른 subspace에서 비어 있는 MarkedBlock을 가져올 수 있습니다. 다만 기존 destructibleBits() bitvector에 표시된 block은 대상에서 제외됩니다. destructible block을 회수하려면 먼저 inline destructor sweep을 거쳐야 하기 때문입니다.

비어 있는 heap block이 서로 다른 JS 객체 타입 pool 사이를 오갈 수 있게 되었습니다. 그 결과 subspace별로 낭비되던 메모리는 줄어들지만, heap layout과 재사용 동작은 달라집니다. JSC의 메모리 grooming을 다루는 입장에서 보면 바로 이 지점이 중요합니다. 한 가지 cell type을 담고 있던 block이 다른 type을 담당하는 directory로 넘어갈 수 있기 때문입니다. 즉 특정 주소 범위가 지금까지 어느 subspace에 속해 있었는지에 대한 가정은, GC cycle을 넘어가면 더 이상 성립하지 않습니다.