Summary
On Windows, every publish_track of a video track retains roughly 40 MB of private memory for the lifetime of the Room. unpublish_track does not release it; only closing/dropping the Room does. An application that starts and stops screen share repeatedly within one session accumulates ~40 MB per start.
Audio track publishes do not leak. Creating the NativeVideoSource + LocalVideoTrack and feeding frames without publishing does not leak either — the retention happens specifically in the publish path.
Environment
- Windows 11 (10.0.26200), x64
- rust-sdks
master @ 0067e100 (also reproduced on 83fa5f2b)
livekit with native-tls, NativeVideoSource 1280×720, is_screencast: true
- Server: local
livekit-server --dev
Reproduction
One Room connection; per cycle: create source + track, publish, feed 30 synthetic I420 frames at ~15 fps, unpublish, drop everything, sleep, measure process memory (K32GetProcessMemoryInfo).
let (room, _events) = Room::connect(URL, &token, RoomOptions::default()).await?;
for i in 1..=5 {
let source = NativeVideoSource::new(VideoResolution { width: 1280, height: 720 }, true);
let track = LocalVideoTrack::create_video_track("t", RtcVideoSource::Native(source.clone()));
let publication = room.local_participant().publish_track(
LocalTrack::Video(track),
TrackPublishOptions {
source: TrackSource::Screenshare,
video_encoding: Some(VideoEncoding { max_bitrate: 4_000_000, max_framerate: 15.0 }),
simulcast: false,
..Default::default()
},
).await?;
for f in 0..30 {
let buffer = I420Buffer::new(1280, 720);
source.capture_frame(&VideoFrame {
rotation: VideoRotation::VideoRotation0,
timestamp_us: f * 66_000,
frame_metadata: None,
buffer,
});
tokio::time::sleep(Duration::from_millis(66)).await;
}
room.local_participant().unpublish_track(&publication.sid()).await?;
drop(source);
tokio::time::sleep(Duration::from_millis(1000)).await;
// measure working set + private bytes here
}
Measurements
Private bytes after each cycle (baseline 9.1 MB, one Room, 5 publish/unpublish cycles):
cycle 1: +41.4 MB
cycle 2: +81.7 MB
cycle 3: +122.2 MB
cycle 4: +162.4 MB
cycle 5: +202.6 MB
Variations tried, all with the same result unless noted:
- Skipping
unpublish_track (publish, then just drop the source/publication): identical growth — unpublish is not the trigger, publish is.
- Feeding 15 vs 60 frames per cycle: identical growth (~41 MB either way) — the retention is a fixed-size per-publish allocation, not per-frame.
- Creating source + track + feeding frames but never publishing: flat (+0.1 MB per cycle).
- Audio (
NativeAudioSource → publish/unpublish per session): flat.
- Closing the Room releases the memory — reconnect-per-cycle tests do not accumulate.
Impact / workaround
Long-lived voice sessions with repeated screen-share start/stop grow unboundedly. We are working around it by publishing the screen-share track once per Room and muting/reusing it across share sessions instead of unpublishing, which avoids the accumulation but keeps one ~40 MB allocation live per Room.
Summary
On Windows, every
publish_trackof a video track retains roughly 40 MB of private memory for the lifetime of the Room.unpublish_trackdoes not release it; only closing/dropping the Room does. An application that starts and stops screen share repeatedly within one session accumulates ~40 MB per start.Audio track publishes do not leak. Creating the
NativeVideoSource+LocalVideoTrackand feeding frames without publishing does not leak either — the retention happens specifically in the publish path.Environment
master@0067e100(also reproduced on83fa5f2b)livekitwithnative-tls,NativeVideoSource1280×720,is_screencast: truelivekit-server --devReproduction
One Room connection; per cycle: create source + track, publish, feed 30 synthetic I420 frames at ~15 fps, unpublish, drop everything, sleep, measure process memory (
K32GetProcessMemoryInfo).Measurements
Private bytes after each cycle (baseline 9.1 MB, one Room, 5 publish/unpublish cycles):
Variations tried, all with the same result unless noted:
unpublish_track(publish, then just drop the source/publication): identical growth — unpublish is not the trigger, publish is.NativeAudioSource→ publish/unpublish per session): flat.Impact / workaround
Long-lived voice sessions with repeated screen-share start/stop grow unboundedly. We are working around it by publishing the screen-share track once per Room and muting/reusing it across share sessions instead of unpublishing, which avoids the accumulation but keeps one ~40 MB allocation live per Room.