为什么c#垃圾收集器不会一直试图释放内存,直到满足请求为止? [英] Why does the c# garbage collector not keep trying to free memory until a request can be satisfied?

查看:95
本文介绍了为什么c#垃圾收集器不会一直试图释放内存,直到满足请求为止?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的代码:

  using System; 

命名空间memoryEater
{
内部类程序
{
private static void Main(string [] args)
{
Console.WriteLine(alloc 1);
var big1 = new BigObject();

Console.WriteLine(alloc 2);
var big2 = new BigObject();

Console.WriteLine(null 1);
big1 = null;

//GC.Collect();

Console.WriteLine(alloc3);
big1 = new BigObject();

Console.WriteLine(done);
Console.Read();
}
}

public class BigObject
{
private const uint OneMeg = 1024 * 1024;
private static int _idCnt;
private readonly int _myId;
私人字节[] [] _bigArray;

public BigObject()
{
_myId = _idCnt ++;
Console.WriteLine(BigObject {0} creating ...,_myId);

_bigArray =新字节[700] [];

for(int i = 0; i <700; i ++)
{
_bigArray [i] = new byte [OneMeg]; (int i = 0; i< OneMeg; i ++)的


(int j = 0; j <700; j ++)
{
_bigArray [j] [i] =(byte)i;
}
}
Console.WriteLine(done);
}

〜BigObject()
{
Console.WriteLine(BigObject {0} finalized,_myId);





$ b我有一个类BigObject ,它在其构造函数中创建了一个700MiB数组,并且有一个finalize方法,除了打印到控制台之外别无其他。在Main中,我创建了两个这样的对象,然后创建第三个对象。然后创建第三个对象。

如果编译为32位(以将内存限制为2个演出),创建第三个BigObject时会引发内存不足异常。这是因为,当第三次请求内存时,请求不能满足,所以垃圾收集器运行。但是,准备收集的第一个BigObject具有终结方法,因此不会被收集,而是放在最终确定队列中并最终确定。垃圾收集器然后停止并抛出异常。但是,如果对GC.Collect的调用没有注释,或者finalize方法被移除,代码将运行正常。



我的问题是,为什么垃圾收集器不是尽其所能满足内存需求?如果它运行了两次(一次完成并再次释放),上面的代码可以正常工作。垃圾收集器不应该继续敲定并收集,直到在抛出异常之前没有更多的内存可以释放为止,并且是否有任何方式将它配置为以这种方式运行(无论是在代码中还是通过Visual Studio)?

解决方案

如果GC能够正常工作并尝试回收内存,您在 big1 = null 之后添加此行。然而,你应该对强制GC进行收集感到忧心忡忡。除非你知道你在做什么,否则不推荐它。

  GC.Collect(); 
GC.WaitForPendingFinalizers(); b


$ b

for-forcing-garbage-collection-in-c-sharp>在C#中强制垃圾收集的最佳实践



什么时候应该使用GC.SuppressFinalize()?



.NET(世代)中的垃圾收集


Consider the code below:

using System;

namespace memoryEater
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine("alloc 1");
            var big1 = new BigObject();

            Console.WriteLine("alloc 2");
            var big2 = new BigObject();

            Console.WriteLine("null 1");
            big1 = null;

            //GC.Collect();

            Console.WriteLine("alloc3");
            big1 = new BigObject();

            Console.WriteLine("done");
            Console.Read();
        }
    }

    public class BigObject
    {
        private const uint OneMeg = 1024 * 1024;
        private static int _idCnt;
        private readonly int _myId;
        private byte[][] _bigArray;

        public BigObject()
        {
            _myId = _idCnt++;
            Console.WriteLine("BigObject {0} creating... ", _myId);

            _bigArray = new byte[700][];

            for (int i = 0; i < 700; i++)
            {
                _bigArray[i] = new byte[OneMeg];
            }

            for (int j = 0; j < 700; j++)
            {
                for (int i = 0; i < OneMeg; i++)
                {
                    _bigArray[j][i] = (byte)i;
                }
            }
            Console.WriteLine("done");
        }

        ~BigObject()
        {
            Console.WriteLine("BigObject {0} finalised", _myId);
        }
    }
}

I have a class, BigObject, which creates a 700MiB array in its constructor, and has a finalise method which does nothing other than print to console. In Main, I create two of these objects, free one, and then create a third.

If this is compiled for 32 bit (so as to limit memory to 2 gigs), an out of memory exception is thrown when creating the third BigObject. This is because, when memory is requested for the third time, the request cannot be satisfied and so the garbage collector runs. However, the first BigObject, which is ready to be collected, has a finaliser method so instead of being collected is placed on the finalisation queue and is finalised. The garbage collecter then halts and the exception is thrown. However, if the call to GC.Collect is uncommented, or the finalise method is removed, the code will run fine.

My question is, why does the garbage collector not do everything it can to satisfy the request for memory? If it ran twice (once to finalise and again to free) the above code would work fine. Shouldn't the garbage collector continue to finalise and collect until no more memory can be free'd before throwing the exception, and is there any way to configure it to behave this way (either in code or through Visual Studio)?

解决方案

Its undeterministic when GC will work and try to reclaim memory.

If you add this line after big1 = null . However you should be carefult about forcing GC to collect. Its not recommended unless you know what you are doing.

GC.Collect();
GC.WaitForPendingFinalizers();

Best Practice for Forcing Garbage Collection in C#

When should I use GC.SuppressFinalize()?

Garbage collection in .NET (generations)

这篇关于为什么c#垃圾收集器不会一直试图释放内存,直到满足请求为止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆