Skip to content

[C++] Memory Leak caused by rs2::syncer #6337

@MojamojaK

Description

@MojamojaK

Required Info
Camera Model D415
Firmware Version 5.12.3
Operating System & Version Windows 10
Platform PC
SDK Version 2.33.1 & 2.34.1
Language C++
Segment Image Processing

SDK build flags

-DCMAKE_BUILD_TYPE=Debug (unrelated - tested: leak also occurs when Release)
-DFORCE_RSUSB_BACKEND=false (unrelated - tested: leak also occurs when true)
-DBUILD_EXAMPLES=false
-DBUILD_WITH_OPENMP=false (unrelated)

Issue Description

There seems to be a huge memory leak when using rs2::syncer when passing
syncer to rs2::sensor::start(syncer) for one or more sensors.

Leak does not occur when using rs2::frame_queue.

I am using Visual Studio's Memory profiler feature to capture heap profile.
According to the profiler, memory for std::shared_ptr<librealsense::frame_archive> allocated in librealsense::make_archive at librealsense::frame_source::init is not deallocated even after the destructor of rs2::syncer is called.

I have provided a sample code which reproduces this every time.
Feel free to tell me if I am doing something I am not supposed to or if there is anyway I can improve SDK usage.

Simple Sample Code for Reproduction

#include <cstdlib>
#include <vector>
#include <iostream>

#include <librealsense2/rs.hpp>

#define LOOP_COUNT 10

typedef struct stream_profile_config
{
	int fps;
	rs2_stream stream_type;
	int stream_index;
	rs2_format format;
	int width;
	int height;
	
} stream_profile_config;

std::tuple<bool, rs2::stream_profile> get_stream_profile(const rs2::sensor &sensor, const stream_profile_config &config)
{
	const std::vector<rs2::stream_profile> stream_profiles = sensor.get_stream_profiles();
	for (const rs2::stream_profile& stream_profile : stream_profiles)
	{
		if (stream_profile.is<rs2::video_stream_profile>())
		{
			const rs2::video_stream_profile video_stream_profile = stream_profile.as<rs2::video_stream_profile>();
			if (video_stream_profile.fps() == config.fps 
				&& video_stream_profile.stream_type() == config.stream_type 
				&& video_stream_profile.stream_index() == config.stream_index
				&& video_stream_profile.format() == config.format
				&& video_stream_profile.width() == config.width
				&& video_stream_profile.height() == config.height)
			{
				return std::make_tuple(true, stream_profile);
			}
		}
	};
	return std::make_tuple(false, stream_profiles[0]);
}

int main(void)
{
	std::cout << "[INFO] Starting Realsense Sandbox Program. " << std::endl;
	std::cout << "[INFO] Librealsense Library Version: " << RS2_API_VERSION_STR << std::endl;
	
	{
		rs2::context context;

		const rs2::device_list device_list = context.query_devices();
		if (device_list.size() < 1)
		{
			std::cout << "[ERROR] NO REALSENSE DEVICES FOUND!" << std::endl;
			return EXIT_FAILURE;
		}

		const rs2::device device = device_list[0];
		if (!device)
		{
			std::cout << "[ERROR] REALSENSE DEVICE INVALID" << std::endl;
			return EXIT_FAILURE;
		}

		const rs2::color_sensor color_sensor = device.first<rs2::color_sensor>();
		const rs2::depth_sensor depth_sensor = device.first<rs2::depth_sensor>();
		if (!color_sensor || !depth_sensor)
		{
			std::cout << "[ERROR] REALSENSE DEVICE SENSOR(S) INVALID" << std::endl;
			return EXIT_FAILURE;
		}

		const std::tuple<bool, rs2::stream_profile> color_stream_profile_result = get_stream_profile(color_sensor, { 6, rs2_stream::RS2_STREAM_COLOR, 0, rs2_format::RS2_FORMAT_BGR8, 1280, 720 });
		const std::tuple<bool, rs2::stream_profile> depth_stream_profile_result = get_stream_profile(depth_sensor, { 6, rs2_stream::RS2_STREAM_DEPTH, 0, rs2_format::RS2_FORMAT_Z16, 1280, 720 });
		if (!std::get<0>(color_stream_profile_result) || !std::get<0>(depth_stream_profile_result))
		{
			std::cout << "[ERROR] REALSENSE SENSOR STREAM PROFILE NOT FOUND" << std::endl;
			return EXIT_FAILURE;
		}

		const rs2::stream_profile &color_stream_profile = std::get<1>(color_stream_profile_result);
		const rs2::stream_profile &depth_stream_profile = std::get<1>(depth_stream_profile_result);

		// rs2::log_to_console(rs2_log_severity::RS2_LOG_SEVERITY_ALL);
		
		for (int loop = 0; loop < LOOP_COUNT; loop++)
		{
			std::cout << "[INFO] LOOP " << loop << std::endl;
			{
				rs2::syncer syncer;
				std::cout << "[INFO] rs2::syncer constructed" << std::endl;

				std::cout << "[INFO] Opening / Starting Sensors" << std::endl;
				color_sensor.open(color_stream_profile);
				depth_sensor.open(depth_stream_profile);

				color_sensor.start(syncer);
				depth_sensor.start(syncer);
				std::cout << "[INFO] Opening / Starting Sensors Complete" << std::endl;

				// Not Retrieving any frames from sensor
				// Leak also occurs when frames are retrieved

				std::cout << "[INFO] Stopping / Closing Sensors" << std::endl;
				color_sensor.stop();
				depth_sensor.stop();
				color_sensor.close();
				depth_sensor.close();
				std::cout << "[INFO] Stopping / Closing Sensors Complete" << std::endl;
			}
			std::cout << "[INFO] rs2::syncer should be destroyed" << std::endl;
			std::cout << "[INFO] Take a snapshot of memory here" << std::endl;
			std::cout << "[INFO] Input Something & press Enter to continue..." << std::endl;
			std::cout << "[INFO] Input \"q\" & press Enter to quit" << std::endl;
			std::string input;
			std::cin >> input;
			if (input == "q")
			{
				break;
			}
		}

		std::cout << "[INFO] Closing Realsense Sandbox Program. " << std::endl;
	}
	std::cout << "[INFO] Take a snapshot of memory here" << std::endl;
	std::cout << "[INFO] Input Something & press Enter to quit..." << std::endl;
	std::string input;
	std::cin >> input;
	return EXIT_SUCCESS;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions