Question T13659
Visible to All Users

Memory leak when uploading images

created 2 years ago

We have a memory leak when a new image is uploaded and it is more apparent when there are already several images uploaded already as a question response. We used memory tools and tracked the issue down to renderPreview() function. Here is how our upload mechanism is laid out:

  1. User clicks on upload files click
  2. User selects an image
  3. The image is stored on our servers as base64
  4. If the server request is successful the uploadSuccessCallBack() is called
  5. This will call renderPreview() function. When the render preview function is called, the memory usage goes up and doesn't come back until we restart the app.

We believe the renderer keeps a copy of the base64 images in memory and doesn't clean.
6. In uploadSuccessCallBack() we concatenate the new image (as base64)to this.question.value. (i.e.
this.question.value = (this.question.value || []).concat(
                {
                  name: r.fileName,
                  type: r.type,
                  content: r.content,
                  fileData: r.fileData
                });
)
This will call renderPreview() function. When the render preview function is called, the memory usage goes up and doesn't come back until we restart the app.

We believe the renderer keeps a copy of the base64 images in memory and doesn't clean. We wonder if there is a better/more efficient way to update the question instead of using .concat().

Show previous comments (5)

    You are very welcome!

    Andrew
    SurveyJS Team

      Hey Andrew thank so much for putting in the fix. However, I am trying to understand what this function tries to achieve and what happens if we just return the value when we have an array instead of iterating through the array. BTW I left a comment in the above PR as well. Feel free to respond to either of them.

      So instead of

      TypeScript
      public static getUnbindValue(value: any): any { if(Array.isArray(value)) { const res = []; for(let i = 0; i < value.length; i ++) { res.push(Helpers.getUnbindValue(value[i])); } return res; } if (!!value && value instanceof Object && !(value instanceof Date)) { const res: any = {}; const keys = Object.keys(value); keys.forEach(key => { const val = Helpers.getUnbindValue(value[key]); if(val !== undefined) { res[key] = val; } }); return res; } return value; }

      We have something similar to :

      TypeScript
      public static getUnbindValue(value: any): any { if(Array.isArray(value)) { return value: } if (!!value && value instanceof Object && !(value instanceof Date)) { const res: any = {}; const keys = Object.keys(value); keys.forEach(key => { const val = Helpers.getUnbindValue(value[key]); if(val !== undefined) { res[key] = val; } }); return res; } return value; }
      AT AT
      Andrew Telnov a year ago

        Hello Salar,
        I have answered here.

        Thank you,
        Andrew
        SurveyJS Team