[PERF] Add hnsw:initial_capacity to reduce memory from HNSW index resizing#6621
Open
takayan0908 wants to merge 1 commit intochroma-core:mainfrom
Open
[PERF] Add hnsw:initial_capacity to reduce memory from HNSW index resizing#6621takayan0908 wants to merge 1 commit intochroma-core:mainfrom
takayan0908 wants to merge 1 commit intochroma-core:mainfrom
Conversation
…quency
When adding many vectors to a collection, the HNSW index starts with
DEFAULT_CAPACITY=1000 and grows by resize_factor=1.2x each time capacity
is exceeded. For a collection of ~3000 vectors, this causes 6+ resize
operations (1000→1200→1440→1728→2074→2489→2987). Each resize_index()
call allocates a new contiguous buffer while the old one is freed — but
memory allocators (glibc, jemalloc) typically do not return these large
freed buffers to the OS, causing RSS to grow far beyond the actual data
size (e.g., 50GB+ RSS for 54MB of vector data).
This commit adds a new `hnsw:initial_capacity` metadata parameter that
allows users to set the initial index capacity to match their expected
dataset size, dramatically reducing the number of resize operations and
the associated memory fragmentation.
Usage:
collection = client.get_or_create_collection(
name="my_collection",
metadata={"hnsw:initial_capacity": 5000}
)
The default value (1000) preserves existing behavior.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Reviewer ChecklistPlease leverage this checklist to ensure your code review is thorough before approving Testing, Bugs, Errors, Logs, Documentation
System Compatibility
Quality
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
hnsw:initial_capacitymetadata parameter that controls the initialmax_elementsfor the HNSW indexDEFAULT_CAPACITYreferences in index initialization and resize logic with the user-configurable valueProblem
When adding many vectors to a collection incrementally, the HNSW index starts at
DEFAULT_CAPACITY=1000and grows byresize_factor=1.2xeach time capacity is exceeded:Each
resize_index()call in hnswlib allocates a new contiguous buffer and frees the old one. However, memory allocators (glibc and jemalloc) typically do not return these large freed buffers to the OS. The old buffers remain mapped in the process address space, causing RSS to grow far beyond actual data requirements.In our production environment, we observed 50GB+ RSS for 54MB of vector data (2786 vectors, 1024-dim embeddings). Analysis of
/proc/PID/smapsrevealed a descending pattern of anonymous memory mappings (7GB, 6GB, 5GB, 4GB...) — each one a ghost of a previous resize operation.Solution
Allow users to pre-size the index to avoid unnecessary resizes:
This follows the existing pattern of
hnsw:*metadata parameters (hnsw:resize_factor,hnsw:batch_size, etc.).Changes
hnsw_params.pyinitial_capacityfield + validatorlocal_hnsw.pyself._params.initial_capacityinstead ofDEFAULT_CAPACITYlocal_persistent_hnsw.pyinit_indexandload_indexpathstest/property/strategies.pyhnsw:initial_capacityto property-based test strategiestest/property/test_schema.pyTest plan
hnsw:initial_capacitywith random valueshnsw:initial_capacity=5000and adding 3000 vectors results in 0 resize operations (vs 6 previously)🤖 Generated with Claude Code