Description
Description
Streaming the stderr and stdout output leads to a severe memory leak.
Reproduce
- Open JupyterLab
- Create a code cell with
or
from time import sleep for i in range(10_000): print('X' * 40, flush=True) sleep(0.001)
from time import sleep import logging for i in range(10_000): logging.warning('X' * 27) # this gives 40 characters sleep(0.001)
- Open Dev Tools → Memory tab
- Record the allocation, run the cell:
or
- See many copies of the string with decreasing sizes:
- See more copies of the string stored as concatenated strings, with retained size much larger than the shallow size:
- See even more copies of the strings stored as slices strings, with retained size much larger than the shallow size:
- See the concatenated strings retain sliced strings, preventing garbage collection:
- See that 2126 MB were allocated in total
- Try re-running with larger iteration number and see Chrome crash
In addition, these two non-native classes are implicated in the problematic retention, ch
which is an minified symbol for yjs.structs.Item
and Hl
which is yjs.structs.ContentString
:
The allocation stack points to thee addText
function which in some code paths creates substrings of the string, and interfaces with the yjs
string methods:
jupyterlab/packages/outputarea/src/model.ts
Lines 611 to 641 in 1f18828
and for yjs.structs.Item
the stack is:
The yjs might be partially to blame as it may store more copies than necessary, but it appears as the core issue might be explained by a long standing (10+ years) bug (feature?) in Chrome and Firefox: substrings retain a copy of the original source string, which in case of streaming where the final string is a composition of all previous substrings can lead to a huge memory leak:
- Chrome: Substring of huge string retains huge string in memory #41480525
- Firefox Do small dependent strings effectively leak large strings? #727615
Note that the Firefox issue was closed last month and Firefox 141 may no longer manifest the bug, but the attempts to fix it in Chrome stalled.
Expected behavior
The resulting strings takes 410 kB (or a small multiple of that) in memory.
Context
- Browser and version: Chrome 137
- JupyterLab version: 4.4.3