• 引发类型为“System.OutOfMemoryException”的异常


    在运维工作中,经常能接到客户的反馈这个:引发类型为“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();
    }
    
    }
    }
    

      

  • 相关阅读:
    串的模式匹配
    Linux_ch02
    Linux操作简介
    Stack&Queue
    单链表
    工作中用到的oracle字符串分割整理
    maven_spring mvc_mina_dome(实体,文件,批传)(spring mina 初学dome)
    求整数和与均值
    简单计算器
    苹果和虫子2
  • 原文地址:https://www.cnblogs.com/50614090/p/9882030.html
Copyright © 2020-2023  润新知