类别:程序开发

日期:2022-01-07 浏览:1966 评论:0

在运维工作中,经常能接到客户的反馈这个:引发类型为“System.OutOfMemoryException”的异常。客户反馈物理内存都还有富余,怎么报内存不足的错误呢!

什么时候会引发System.OutOfMemoryException:操作系统无法满足GC对连续内存块的请求,则会发生System.OutOfMemoryException

可能原因
1:内存真的不够了,连虚拟内存都用完了。
2:内存还有,但碎片化严重,无法找到合适的连续内存块。

一些常见的原因
1、系统里缓存了大量的数据,没有及时释放。应该控制缓存的数据大小,缓存失效的时间。
2、操作的大数据的文件或者DataTable。应该分块读取。
3、本地资源泄漏。
解决方案:
3.1 应该及时释放本地资源
3.2 使用IDisposable模式

4、大量的对象被固定,不能被压缩移动,导致内存产生大量碎片。
解决方案:

4.1 如果固定对象大约在同一时间分配,则每两个对象之间的碎片更小
4.2 优先初始化,因为较旧的对象位于堆的底部,但大多数可用空间都是在堆顶部生成的。
4.3 固定对象的时间越短,GC就越容易压缩堆

测试环境:物理内存8G,64位操作系统
示例一、物理内存,虚拟内存都被消耗完,抛出System.OutOfMemoryException的异常

using System;
using System.Collections.ObjectModel;

namespace OutOfMemoryExample
{
    class Program
    {
        static List<byte[]> _root = new List<byte[]>();
        static void Main(string[] args)
        {
            try
            {
               int i = 1;
               while (true)
               {

                  var smallObject = new byte[64 * 1024];//小于85000byte的对象存在小对象堆(SOH – small object heap)
                  Console.WriteLine(string.Format("{0}K", i * 64));
                  _root.Add(smallObject);//用静态List对象不断新增小对象,由于静态对象不会被回收,最终会发现物理内存和虚拟内存都耗尽,抛出OutOfMemory异常
                  i++;
               }
            }
            catch (Exception ex)
            {
               Console.WriteLine(ex);
            }

            Console.Read();
         }

     }
       
}

示例二、物理内存还有4G,虚拟内存都被消耗完(22G),

大对象(大于85000byte)存储到大对象堆,大对象堆属于第二代堆,垃圾回收时不会压缩内存,分配一个大对象时,优先尝试在大对象堆的尾部进行分配,如果尾部空间不足,就会尝试向操作系统请求更多的内存空间,

前面都失败失败时,才会重新搜索之前无效对象留下的内存空隙。如果没有找到连续的内存块,抛出System.OutOfMemoryException的异常。

疑问:为什么物理内存还有,大对象堆为什么向操作系统申请不到内存?

我推测是这些剩余的内存被一些程序给预留了,或者没有大的内存块。

using System;
using System.Collections.ObjectModel;
 
namespace OutOfMemoryExample
{
    class Program
    {
        static List<byte[]> _root = new List<byte[]>();
        static void Main(string[] args)
        {
            try
            {
                for(int i=1;i<500000;i++)
                {
 
                    var largeObject = new byte[100 * 1024];//大于85000byte的对象存在一个大对象堆(LOH –large object heap)
                    Console.WriteLine(string.Format("第{0}次:{1}K",i, i * 100));
                    _root.Add(largeObject);//用静态List对象不断新增对象,由于静态对象不会被回收,最终会发现虚拟内存都耗尽,抛出OutOfMemory异常!但物理内存还有4G
                    i++;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
 
            Console.Read();
        }
 
    }
}


本文标题:引发类型为“System.OutOfMemoryException”的异常
本文链接:https://vtzw.com/post/831.html
作者授权:除特别说明外,本文由 零一 原创编译并授权 零一的世界 刊载发布。
版权声明:本文不使用任何协议授权,您可以任何形式自由转载或使用。
 您阅读本篇文章共花了: 

历史上的今天
01月
07

 可能感兴趣的文章

评论区

发表评论 / 取消回复

必填

选填

选填

◎欢迎讨论,请在这里发表您的看法及观点。