引发类型为“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();
}

}
}

  

转载于:https://www.cnblogs.com/50614090/p/9882030.html

n叉树是一种每个节点最多有n个子节点的树结构,其遍历主要包括前序遍历、中序遍历和后序遍历,这三种遍历顺序可以递归地应用到每一个子节点。以下是使用C语言实现n叉树基本遍历的一个简单示例: ```c #include <stdio.h> #include <stdlib.h> // 定义一个结点结构体 typedef struct Node { int data; // 节点数据 struct Node** children; // 子节点指针数组 int num_children; // 子节点个数 } Node; // 创建新节点 Node* create_node(int data) { Node* node = (Node*)malloc(sizeof(Node)); node->data = data; node->num_children = 0; node->children = malloc(10 * sizeof(Node*)); // 假设每个节点最多有10个子节点 return node; } // 前序遍历:根 -> 左 -> 右 void preorder_traversal(Node* root) { if (root != NULL) { printf("%d ", root->data); for (int i = 0; i < root->num_children; ++i) preorder_traversal(root->children[i]); } } // 中序遍历:左 -> 根 -> 右 void inorder_traversal(Node* root) { if (root != NULL) { for (int i = 0; i < root->num_children; ++i) inorder_traversal(root->children[i]); printf("%d ", root->data); } } // 后序遍历:左 -> 右 -> 根 void postorder_traversal(Node* root) { if (root != NULL) { for (int i = 0; i < root->num_children; ++i) postorder_traversal(root->children[i]); printf("%d ", root->data); } } // 主函数测试 int main() { // 初始化n叉树并添加节点... // 这里省略了具体的n叉树创建过程 Node* root = ...; // 获取n叉树的根节点 printf("Preorder traversal: "); preorder_traversal(root); printf("\nInorder traversal: "); inorder_traversal(root); printf("\nPostorder traversal: "); postorder_traversal(root); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值