Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 742|回复: 0

String引起的OutOfMemory异常 + 如何计算C#对象所占内存的大小

[复制链接]
  • TA的每日心情
    奋斗
    2025-3-18 14:43
  • 签到天数: 805 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    73万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    731050
    发表于 2021-5-28 22:02:40 | 显示全部楼层 |阅读模式

    问题:

    在一个高并发的接口经常会报错OutOfMemory,检查了代码和服务器各种配置之后感觉一切都正常……

    百思不得其解,只能把报错的一段拿出来测试,

    最后发现是黄色这段代码出了问题:

     1         public void TestOutOfMemory()
     2         {
     3             var result = string.Empty;  4             string BSID = "MH_SYS";
     5             string FType = "USR";
     6             DirectoryInfo outFolder = new DirectoryInfo(ConfigurationManager.AppSettings["filePath"]);
     7             var temp = outFolder.GetDirectories().Where(x => !x.Name.Contains("bak"));
     8             if (temp.Count() > 0)
     9             {
    10                 try
    11                 {
    12  GC.Collect(); 13  GC.WaitForFullGCComplete(); 14                     long start = GC.GetTotalMemory(true); 15 
    16                     var timeSpan = temp.OrderByDescending(x => x.Name).FirstOrDefault().Name;//获取timeSpan文件夹名称
    17                     DirectoryInfo inFolder = new DirectoryInfo(ConfigurationManager.AppSettings["filePath"] + timeSpan + @"\" + BSID + @"\" + FType + @"\");
    18                     if (inFolder.GetFiles().Count() > 0)
    19                     {
    20                         var list = inFolder.GetFiles().OrderBy(x => Convert.ToInt16(x.Name.Split('.')[0]));
    21                         foreach (var item in list)
    22                         {
    23                             using (FileStream fs = new FileStream(item.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
    24                             {
    25                                 int fsLen = (int)fs.Length;
    26                                 byte[] heByte = new byte[fsLen];
    27                                 int r = fs.Read(heByte, 0, heByte.Length);
    28                                 result += System.Text.Encoding.UTF8.GetString(heByte); 29                             }
    30                         }
    31                     }
    32 
    33  GC.Collect(); 34  GC.WaitForFullGCComplete(); 35                     long end = GC.GetTotalMemory(true); 36                     long size = end - start; 37 
    38                     Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "\n" + (size/1024/1024) + "M\n" + result.GetHashCode() + "\n" + result.Substring(0,1000) + "\n\n\n\n");
    39                 }
    40                 catch (Exception e)
    41                 {
    42                     throw e;
    43                 }
    44             }
    45         }

    用日志记录了下result这个String字符串的哈希编码,发现在多个并发的情况下,都是一样的,说明GC并没有及时回收这个String。

    也就是说接口并发时用的都是同一个String对象,加上接口所需要返回的内容很大,每个大概有30M左右,测试当5个并发的时候,占用内存就到了600-700M,10个并发的时候内存占用到了1.5G左右,所以OutOfMemory也不奇怪啦。

    PS:计算C#对象所占内存的大小

     请参考上面代码中灰色部分~~

     

    解决方案:

    找到问题根源之后很简单,只要用StringBuilder代替String,用下面代码替换上文黄色部分即可

    StringBuilder result = new StringBuilder();
    
    result.Append(System.Text.Encoding.UTF8.GetString(heByte));

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-4-21 07:01 , Processed in 0.060939 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表