Avoid excessive heap allocations in HPACK's dynamic table #20
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.
Two improvements that can help minimizing heap usage by the HPACK module:
1: Set table size in octets instead of number of entries
We were using the struct size for the dynamic table, creating a buffer which could hold up to 4096
HTTP2HeaderTableField
entries. RFC 7540 specifies that the default value for theSETTINGS_HEADER_TABLE_SIZE
parameter is, instead, 4096 octets. For this reason the initial dynamic table size is now computed as 4096 / (size of an emptystruct HTTP2HeaderTableField
) which is 32 octets. A test case has been added to make sure that this value is respected.2: Avoid calling FixedRingBuffer.capacity
Profiling heap allocations with
buildOptions "profileGC"
and sending a single HTTP/2 request to the webserver, the heaviest heap allocation is performed by the forced use ofFixedRingBuffer.capacity
in the constructor for the internalDynamicTable
, called when the main HPACK table for the HTTP/2 server is created.Since we are using a fixed, default value for the header table size, it seems unnecessary to call
capacity
when most of the time the table size is set to 4096. It makes more sense to allow for two tables which can be used behind a unique interface:m_table
is a statically-allocated table with size of 4096, which gets created on struct DynamicTable initializationm_extraTable
is a dynamically allocated table which gets initialized iff the constructor for DynamicTable is called with a size parameter > 4096. Its size is therefore set toms - 4096
and its entries are filled only whenm_table
is full.Note that most clients (especially browsers) use the default value of 4096 octets when initializing a HTTP/2 connection, in which case the extra table is not initialized and the HPACK
IndexingTable
should not require dynamic allocations at all.