Qustion of memory leak gst-plugin based on dsexample

hi this is function of my custom plugin based on dsexample

static GstFlowReturn
gst_menudraw_prepare_output_buffer(GstBaseTransform * btrans, GstBuffer * inbuf, GstBuffer ** outbuf)
{
GstMenuDraw *menudraw = GST_MENUDRAW (btrans);
GstFlowReturn flow_ret = GST_FLOW_ERROR;
GstMapInfo out_map_info;
DrawParam DrawParam;
NvBufSurface *outsurface = NULL;
NvBufSurfaceCreateParams create_params;
NvDsBatchMeta *batch_meta = NULL;
NvDsFrameMeta *frame_meta = NULL;
NvDsMeta *meta = NULL;

//g_print (“Prepare start\n”);
//*outbuf = inbuf;
//return GST_FLOW_OK;

if (menudraw->inter_buf)
NvBufSurfaceDestroy (menudraw->inter_buf);
menudraw->inter_buf = NULL;

/* An intermediate buffer for NV12/RGBA to BGR conversion will be

  • required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */
    create_params.gpuId = menudraw->gpu_id;
    create_params.width = menudraw->processing_width;
    create_params.height = menudraw->processing_height;
    create_params.size = 0;
    create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
    create_params.layout = NVBUF_LAYOUT_PITCH;
    #ifdef aarch64
    create_params.memType = NVBUF_MEM_DEFAULT;
    //g_print(“set surface memtype nvbuf_mem_dafault\n”);
    #else
    create_params.memType = NVBUF_MEM_CUDA_UNIFIED;
    #endif
    //Make GST Buffer
    if (NvBufSurfaceCreate (&(menudraw->inter_buf), 1,
    &create_params) != 0) {
    GST_ERROR (“Error: Could not allocate internal buffer for menudraw”);
    goto error;
    }
    menudraw->inter_buf->numFilled = 1;

*outbuf = NULL;
*outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_ZERO_PREFIXED, menudraw->inter_buf, sizeof(NvBufSurface), 0, sizeof(NvBufSurface), NULL, NULL);
//g_print(“m1\n”);
batch_meta = nvds_create_batch_meta(1);
//g_print(“m2\n”);
meta = gst_buffer_add_nvds_meta (*outbuf , batch_meta, NULL, copy_user_meta, release_user_meta);
//g_print(“m3\n”);
meta->meta_type = NVDS_BATCH_GST_META;
batch_meta->base_meta.batch_meta = batch_meta;
batch_meta->base_meta.copy_func = copy_user_meta;
batch_meta->base_meta.release_func = release_user_meta;
batch_meta->max_frames_in_batch = 1;
frame_meta = nvds_acquire_frame_meta_from_pool(batch_meta);
//g_print(“m4\n”);
nvds_add_frame_meta_to_batch(batch_meta, frame_meta);
//g_print(“m5\n”);
// Some important parameters to fill
frame_meta->pad_index = 0;
frame_meta->source_id = 0;
frame_meta->buf_pts = 0;
frame_meta->ntp_timestamp = 0;
frame_meta->frame_num = 0;
frame_meta->batch_id = 0;
frame_meta->source_frame_width = 1024;
frame_meta->source_frame_height = 600;
frame_meta->num_surfaces_per_frame = 1 ;

CHECK_CUDA_STATUS (cudaSetDevice (menudraw->gpu_id),
“Unable to set cuda device”);

memset (&out_map_info, 0, sizeof (out_map_info));
if (!gst_buffer_map (*outbuf, &out_map_info, GST_MAP_READWRITE)) {
g_print (“Error: Failed to out map gst buffer\n”);
goto error;
}
outsurface = (NvBufSurface *) out_map_info.data;
GST_DEBUG_OBJECT (menudraw,“Processing Frame Surface %p\n”,outsurface);
if (CHECK_NVDS_MEMORY_AND_GPUID (menudraw, outsurface))
{
g_print (“Error: Check NVDS Memory And Gpu id\n”);
goto error;
}
//NvBufSurfaceMemSet(outsurface, 0, 0, 0);

/*g_print(“debug surface batchsize %u\n”, outsurface->batchSize);
g_print(“debug surface numfilled %u\n”, outsurface->numFilled);
g_print(“debug surface gpuid %u\n”, outsurface->gpuId);

g_print(“debug surface0 num planes %u\n”, outsurface->surfaceList[0].planeParams.num_planes);
g_print(“debug surface0 width %u\n”, outsurface->surfaceList[0].planeParams.width[0]);
g_print(“debug surface0 height %u\n”, outsurface->surfaceList[0].planeParams.height[0]);
g_print(“debug surface0 pitch %u\n”, outsurface->surfaceList[0].planeParams.pitch[0]);
g_print(“debug surface0 offset %u\n”, outsurface->surfaceList[0].planeParams.offset[0]);
g_print(“debug surface0 psize %u\n”, outsurface->surfaceList[0].planeParams.psize[0]);
g_print(“debug surface0 mapaddr %u\n”, outsurface->surfaceList[0].mappedAddr.addr[0]);

g_print(“debug surface0 bytesPerPix %u\n”, outsurface->surfaceList[0].planeParams.bytesPerPix[0]); */

if (NvBufSurfaceMap (outsurface, 0, 0, NVBUF_MAP_READ_WRITE) != 0){
g_print(“Draw surface map Error\n”);
return GST_FLOW_ERROR;
}
NvBufSurfaceSyncForCpu (outsurface, 0,0);

//DrawParam = Process_Draw_Update_Func[menudraw->page_num](menudraw, inbuf);

//Process_Draw_Menu(outsurface, &DrawParam );

NvBufSurfaceSyncForDevice (outsurface, 0,0);
if (NvBufSurfaceUnMap (outsurface, 0,0)){
g_print(“Draw surface unmap Error\n”);
goto error;
}

//g_print (“Prepare OK\n”);
flow_ret = GST_FLOW_OK;
error:
gst_buffer_unmap (*outbuf, &out_map_info);

return flow_ret;
}

this seems to be throw some memory leak but i don’t know why & where occur memory leak

can you help me ??

gstmenudraw.cpp (81.6 KB)
here is my source

I posted a similar question before, but the thread didn’t work, so I wrote it again.

information
input source : 30fps
memory leak

          total        used        free      shared  buff/cache   available

Mem: 4058400 1636060 1078028 28668 1344312 2431384
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1637608 1076480 28668 1344312 2437772
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1638384 1075704 28668 1344312 2439428
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1639756 1074328 28668 1344316 2427688
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1640936 1073148 28668 1344316 2426508
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1641756 1072328 28668 1344316 2428120
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1642248 1071832 28668 1344320 2427624
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1642032 1072048 28668 1344320 2427840
Swap: 2029184 0 2029184

          total        used        free      shared  buff/cache   available

Mem: 4058400 1642368 1071708 28668 1344324 2427504
Swap: 2029184 0 2029184

The gstdsexample.c is working in “in-place” mode. But your codes look like working in normal mode. Please make sure the input gst buffer and output gst buffer are create, map, unmap in right place and right way.
https://gstreamer.freedesktop.org/documentation/base/gstbasetransform.html?gi-language=c

Hi @Fiona.Chen

i think i used “Create,Destroy” the Surface and “Make, Map, Unmap” the outbuffer in right place, can you tell me where i wrong ?

  1. i Destroyed the menudraw->inter_buf every times when call prepare_output_buffer
if (menudraw->inter_buf)
NvBufSurfaceDestroy (menudraw->inter_buf);
menudraw->inter_buf = NULL;
  1. set create param for new surface & create surface
	/* An intermediate buffer for NV12/RGBA to BGR conversion  will be
	required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */      
	create_params.gpuId  = menudraw->gpu_id;
	create_params.width  = menudraw->processing_width;
	create_params.height = menudraw->processing_height;
	create_params.size = 0;
	create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
	create_params.layout = NVBUF_LAYOUT_PITCH;
	#ifdef __aarch64__
	create_params.memType = NVBUF_MEM_DEFAULT;
	g_print("set surface memtype nvbuf_mem_dafault\n");
	#else
	create_params.memType = NVBUF_MEM_CUDA_UNIFIED;
	#endif
	//Make GST Buffer
	if (NvBufSurfaceCreate (&(menudraw->inter_buf), 1,
		  &create_params) != 0) {
	GST_ERROR ("Error: Could not allocate internal buffer for menudraw");
	goto error;
	}
	menudraw->inter_buf->numFilled = 1;
  1. create gstbuffer to the outbuf use created surface
    *outbuf = NULL;
	*outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_ZERO_PREFIXED, menudraw->inter_buf, sizeof(NvBufSurface), 0, sizeof(NvBufSurface), NULL, NULL);
  1. make meta and into the outbuf

batch_meta = nvds_create_batch_meta(1);
//g_print(“m2\n”);
meta = gst_buffer_add_nvds_meta (*outbuf , batch_meta, NULL, copy_user_meta, release_user_meta);
//g_print(“m3\n”);
meta->meta_type = NVDS_BATCH_GST_META;
batch_meta->base_meta.batch_meta = batch_meta;
batch_meta->base_meta.copy_func = copy_user_meta;
batch_meta->base_meta.release_func = release_user_meta;
batch_meta->max_frames_in_batch = 1;
frame_meta = nvds_acquire_frame_meta_from_pool(batch_meta);
//g_print(“m4\n”);
nvds_add_frame_meta_to_batch(batch_meta, frame_meta);
//g_print(“m5\n”);
// Some important parameters to fill
frame_meta->pad_index = 0;
frame_meta->source_id = 0;
frame_meta->buf_pts = 0;
frame_meta->ntp_timestamp = 0;
frame_meta->frame_num = 0;
frame_meta->batch_id = 0;
frame_meta->source_frame_width = 1024;
frame_meta->source_frame_height = 600;
frame_meta->num_surfaces_per_frame = 1 ;

  1. outbuf map
memset (&out_map_info, 0, sizeof (out_map_info));
	if (!gst_buffer_map (*outbuf, &out_map_info, GST_MAP_READWRITE)) {
	 g_print ("Error: Failed to out map gst buffer\n");		
	 goto error; 
	}	     
	outsurface = (NvBufSurface *) out_map_info.data;
	GST_DEBUG_OBJECT (menudraw,"Processing Frame Surface %p\n",outsurface);
	if (CHECK_NVDS_MEMORY_AND_GPUID (menudraw, outsurface))
	{
	   g_print ("Error: Check NVDS Memory And Gpu id\n");
	goto error;
	}
  1. map surface
if (NvBufSurfaceMap (outsurface, 0, 0, NVBUF_MAP_READ_WRITE) != 0){	
		g_print("Draw surface map Error\n");
		return GST_FLOW_ERROR;
	}
	NvBufSurfaceSyncForCpu (outsurface, 0,0);	
  1. drawing
 DrawParam = Process_Draw_Update_Func[menudraw->page_num](menudraw, inbuf);
	Process_Draw_Menu(outsurface, &DrawParam );
  1. unmap surface
NvBufSurfaceSyncForDevice (outsurface, 0,0);	
	if (NvBufSurfaceUnMap (outsurface,  0,0)){
		g_print("Draw surface unmap Error\n");
		goto error;
	}
  1. outbuf unmap

gst_buffer_unmap (*outbuf, &out_map_info);

this is i did.

pipeline is src - streammux - menudraw - osd -…

i wonder where is the problem

thanks…

Is there anyone who can help?

Since it is a whole new plugin and you are using some deepstream apis. Can you identify whether the memory leak is caused by deepstream apis?

Hi Fiona.Chen

i tried return before making batch_meta(4.make meta ~~~ of last reply) In this situation, no memory leak occurred.

I think I made a mistake in the free batchmeta, or something was missing.

could you advise to me ???

I think the problem exists with your codes in gst_menudraw_prepare_output_buffer(), you create new batch meta with nvds_create_batch_meta() function which is provided by DeepStream, but you give the wrong “copy_func” and “release_func” with gst_buffer_add_nvds_meta(), it can not release the batch meta correctly because you don’t know how batch meta is created and the implementation in your release_user_meta() is wrong. It should be “nvds_batch_meta_copy_func” and “nvds_batch_meta_release_func” which can really copy and release the batch meta. Please check the definition of gst_buffer_add_nvds_meta() function and nvds_batch_meta_release_func() in the nvdsmeta.h file.

Hi @Fiona.Chen

this is my copy & release function based on deepstream_user_metadata.cpp

/* copy function set by user. "data" holds a pointer to NvDsBatchMeta*/
static gpointer copy_user_meta(gpointer data, gpointer user_data)
{  
  NvDsBatchMeta *src_batch_metadata = (NvDsBatchMeta*)data;
  NvDsBatchMeta *dst_batch_metadata = (NvDsBatchMeta*)g_malloc0(sizeof(NvDsBatchMeta));
  memcpy(dst_batch_metadata, src_batch_metadata, sizeof(NvDsBatchMeta));
  g_print("batch meta copy \n");
  return (gpointer)dst_batch_metadata;
}

/* release function set by user. "data" holds a pointer to NvDsBatchMeta*/
static void release_user_meta(gpointer data, gpointer user_data)
{
  NvDsBatchMeta *batch_meta = (NvDsBatchMeta *) data;
  NvDsFrameMeta *frame_meta = nvds_acquire_frame_meta_from_pool(batch_meta);
  
  if(frame_meta)
  {
	  //g_print("frame meta free \n");
	  g_free(frame_meta);
	  frame_meta = NULL;
  }
  
  if(batch_meta) 
  {	  
	//g_print("batch meta free \n");
    g_free(batch_meta);
    batch_meta = NULL;
  }  
} 

i use only batch & frame meta data (user meta don’t use)
so I think ‘release_user_meta’ only needs to release framemeta and batchmeta,
Is there anything else my release func need?

Please use “nvds_batch_meta_copy_func” and “nvds_batch_meta_release_func”, DeepStream has provided them.

1 Like

ah… sorry I’ve been looking at the file gst_nvdsmeta.h
I’ll try again and reply!

@Fiona.Chen

your suggestion show perfect

Thank you so much, i spending months on this problem.