Description
- Version:
$ node -p process.versions
{
node: '14.2.0',
v8: '8.1.307.31-node.33',
uv: '1.37.0',
zlib: '1.2.11',
brotli: '1.0.7',
ares: '1.16.0',
modules: '83',
nghttp2: '1.40.0',
napi: '6',
llhttp: '2.0.4',
openssl: '1.1.1g',
cldr: '36.1',
icu: '66.1',
tz: '2019c',
unicode: '13.0'
}
-
Platform:
Darwin <host> 19.4.0 Darwin Kernel Version 19.4.0: Wed Mar 4 22:28:40 PST 2020; root:xnu-6153.101.6~15/RELEASE_X86_64 x86_64
and node docker imagenode:13.13.0-alpine
-
Subsystem: https
What steps will reproduce the bug?
I have created a script to reproduce at https://github.com/mgilbey/node-tls-wrap
The script runs a TLS server and https Agent to be self contained, but only the Agent is needed to reproduce the problem with a HTTPS server to connect to. The classes are only used to help identify which objects are holding references in the heap snapshots.
The script will open 100 connections, send and receive two HTTP requests on each connection (demonstrating keep-alive functions as expected) and then lets the sockets close due to the keep-alive timeout. This repeats five times, leaving 501 TLSWrap objects in memory. The scripts forces a garbage collection, and then collects a heap dump before exiting.
The agent reports the expected number of active / free sockets (never more than 100).
How often does it reproduce? Is there a required condition?
The script will consistently reproduce the issue.
I believe the salient points for reproduction are:
- https Agent with keepAlive enabled
- The number of open sockets never exceeds the maxSockets Agent option.
- Sockets are closed due to the keepAlive timeout specified by the Agent being reached.
What is the expected behavior?
TLSWrap and TLSSocket objects are garbage collected when the socket from the agent is closed due to the keep-alive timeout, and no further keep-alive socket re-use is possible.
What do you see instead?
TLSWrap and TLSSocket objects will grow in memory until the old-space heap limits are reached at e.g. 10 or 300 MB limits. The number of TLSWrap and TLSSocket objects in memory will exceed the maxSockets, maxFreeSockets or maxCachedSessions Agent options.
An allocation timeline and heap snapshot are also included in the repository.
Each TLSWrap object has four retainers, although none appear to be the https Agent.
Additional information
To demonstrate the process crashing due to heap limits, run with --max-old-space-size=10
and increase the number of iterations on line 128 to 50. You can increase heap and the number of iterations should you be more patient.
The issue does not reproduce with the http Agent.
The cause appears to be very similar to resolved issue #19859 that affected the http Agent, particularly the reference to the open sockets being less than the maxSockets option.