Reduce per-call cost of the JS/C++ boundary - #1300
Conversation
|
I don't know if CI failure is my fault, but I've seen it fail other times too. |
|
AFAIK It ( |
|
interesting, but we already tried the stringview and it broke. so
reintroduction has to be thoroughly tested
Den ons 19 aug. 2026 17:37Wojciech Wierchoła ***@***.***>
skrev:
… *webcarrot* left a comment (uNetworking/uWebSockets.js#1300)
<#1300 (comment)>
AFAIK It allow DDOS OOM by spamming "random" headers names.
—
Reply to this email directly, view it on GitHub
<#1300?email_source=notifications&email_token=A2NMOMKMZFRJUKJKZHNJMEL5KXCT5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMZUGQ2DANZXHEZ2M4TFMFZW63VKON2WE43DOJUWEZLEUVSXMZLOOSWGM33PORSXEX3DNRUWG2Y#issuecomment-5344407793>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/A2NMOMJ4VXJ6HQ5IFBA3M7T5KXCT5AVCNFSNUABFKJSXA33TNF2G64TZHMYTIMRWGMYTCOJRHNEXG43VMU5TKMJZGAZDINBRHE42C5QC>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/A2NMOMPAX42HR5LQ77GXFG35KXCT5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMZUGQ2DANZXHEZ2M4TFMFZW63VKON2WE43DOJUWEZLEUVSXMZLOOSVGM33PORSXEX3JN5ZQ>
and Android
<https://github.com/notifications/mobile/android/A2NMOMPM5PQZDY3AGNI5HZL5KXCT5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMZUGQ2DANZXHEZ2M4TFMFZW63VKON2WE43DOJUWEZLEUVSXMZLOOSXGM33PORSXEX3BNZSHE33JMQ>.
Download it today!
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
|
Both objections deserved a proper answer rather than a claim, so I have pushed On the ValueView history. You are right, and it is the reason the test exists. #1262 took The test compares bytes rather than decoded text, since decoded text hides a wrong encoding behind a replacement character. Cases: ASCII, the exact string from #1280, I checked the test can actually fail rather than only pass: simulating what the reverted code did, a Latin-1 copy of the one-byte buffer, three cases go red, the #1280 string, On interning and memory. I could not reproduce an OOM. V8's string table holds weak references, so an internalized string nobody points at is collected. Measured on Node 26: one million unique property keys, which is how V8 internalizes, take 43 MB and the heap returns to its exact starting value after a collection, zero retained. The test carries a smaller version of that, 5000 unique header names over 500 requests, and asserts the heap grows less than 8 MB across a gc; it measures about 1 MB here. What is fair in the objection is the cost, not the leak: interning hashes and looks up the table per distinct name, so random header names are more expensive than before, and the table grows between major collections. That is also why the PR body says iterating headers without using the keys gets about 5% slower. If that trade reads wrong for a server that cannot choose its clients, dropping One caveat on where this runs: both workflows trigger on pushes to master and clone upstream, so the new test cannot run in this PR's CI. Locally it is |
Every string argument crossing from JS to C++ pays two full passes (
Utf8Length+WriteUtf8). Since V8 12.5,String::ValueViewlets one-byte ASCII strings (header keys and values, status, typical bodies) cross with a single scan + memcpy. Older V8 keeps the old path.Smaller items with the same goal:
onAbortedstores the callback in an internal field of res: one global handle per request instead of two, and the capture now fits MoveOnlyFunction inline storage (same for onData/onDataV2/onWritable)tryEndreturns viabulk Array::Newinstead of twoObject::SetNumbers (Node 26 win-x64, min of 5 interleaved runs, ns/op): getHeader 96 -> 81, onAborted install 127 -> 67, forEach collected into a headers object 2599 -> 1999, method dispatch 52 -> 48. End to end (status + 8 headers + 1KB body, pipelined keep-alive, 9 runs): mean 102k -> 106k req/s, median 102k -> 108k. Note: iterating headers without using the keys gets ~5% slower from the interning, the object building case is what Express layers do on every request.
Functional checks pass on both builds: forEach pairs unchanged, abort fires and invalidates res, tryEnd shape unchanged.