【问题标题】:Abandoned memory in posting image data to server将图像数据发布到服务器时的废弃内存
【发布时间】:2021-03-13 01:32:42
【问题描述】:

在将图像数据发布到服务器时显示内存消耗量很大并且它没有释放。以下源代码中的reportModel 具有base64 字符串图像数据。这是源代码的快照,

public async Task<FaultReportResponseModel> ReportFault(ReportFaultRequestModel reportModel)
    {
        try
        {
            App.IsConnectedToInternet(true);
            reportModel.Token = App.WebOpsToken;

            //var httpContent = CreateHttpContent(reportModel);

            var jsonBody = JsonConvert.SerializeObject(reportModel);
            _log.Trace("ReportFault api jsonBody length: {0}", jsonBody.Length);

            var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");

            AddAuthorizationHeader();

            string serviceURL;
            if (reportModel.IssueType == IssueTypes.CantFind)
            {
                serviceURL = Constants.CantFindSvcURL;
            }
            else
            {
                serviceURL = Constants.ReportFaultSvcURL;
            }

            //var url = string.Format("{0}{1}", Constants.DataSVCBaseURL, serviceURL);
            var url = GetURLStringForService(serviceURL, ServiceType.WebOpsData);

            var response = await _restClient.PostAsync(url, content);
            var responseStr = await response.Content.ReadAsStringAsync();
            var parsedResponse = JsonConvert.DeserializeObject<FaultReportResponseModel>(responseStr);
            _log.Trace("Uploaded fault text: {0}", parsedResponse.OK);

            content.Dispose();

            return parsedResponse;
        }
        catch (Exception ex)
        {
            _log.Trace("Exception: {0}", ex.Message);
        }
        return null;
    }

内存占用的快照,

这表明 Json 序列化正在占用内存并且从未被释放。由于这个废弃的内存,经过几次图片上传应用程序崩溃。

我试过了,

  • 使用流内容发布到服务器。在这种情况下,它显示 Stream 中的内存问题。问题指针已更改,但问题相同。
  • 在网上我发现是因为Large Object Heap,所以我尝试手动调用GC,但内存占用没有变化。

任何解决此问题的帮助或提示都会有所帮助。

【问题讨论】:

  • 请重新阅读minimal reproducible example 发布代码指南 - 代码图像不正确,您需要确保示例实际演示了问题。
  • 我不确定这里有问题
  • 您的字符串很可能足够大,可以在 LOH 上结束。这意味着它将一直保留在那里,直到发生完整的 GC (Gen2)。及时拍摄单个快照不足以查看是否存在泄漏。
  • 问题中提到的 @JohanP 是 LOH 的候选者,但有什么解决方案可以删除它?或者你需要什么额外的细节来帮助我或指出我应该研究的领域。
  • @Iducool 你在用什么HttpClient

标签: c# xamarin xamarin.ios json.net


【解决方案1】:

您正在 LOH 上创建大块内存。这可能不是内存堆,尽管它绝对不是高吞吐量应用程序的最佳选择

假设您想在 序列化 上实际使用 Json.Net,您可以使用 JsonTextWriter 实现此目的并直接序列化为流(理想情况下是 HttpClient @987654327 @)。请注意,Test.Json 也有一个非常有效的序列化流方法。

要访问HttpClient 中的底层NetworkStream,您可以创建一个派生的HttpContent

示例

public class SerializedStreamedContent<T> :HttpContent
{
   private readonly T _value;
   public SerializedStreamedContent(T value) => _value = value;
   protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context)
   {
      try
      {
         using var writer = new StreamWriter(stream, leaveOpen:true);
         using var jsonWriter = new JsonTextWriter(writer);
         var ser = new JsonSerializer();
         ser.Serialize(jsonWriter, _value);
         jsonWriter.Flush();
         return Task.CompletedTask;
      }
      catch (Exception e)
      {
         return Task.FromException(e);
      }
   }
   protected override bool TryComputeLength(out long length)
   {
      length = -1;
      return false;
   }
}

注意 1:这不是一个完整的解决方案,只是一个示例。使用这种方法需要权衡许多因素

注意 2:在 .Net 5 中有一个 JsonContent Class,它通过 Text.Json 实现(以及更多)为您完成所有这些

【讨论】:

猜你喜欢
  • 2014-06-13
  • 2012-12-11
  • 2012-08-15
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 2019-12-16
相关资源
最近更新 更多