C# 如何让.NET积极地进行垃圾收集?

C# 如何让.NET积极地进行垃圾收集?,c#,.net,memory-management,garbage-collection,C#,.net,Memory Management,Garbage Collection,我有一个用于图像处理的应用程序,我发现自己通常分配4000x4000 ushort大小的数组,以及偶尔的浮点等。目前,该应用程序中的.NET framework可能会随机崩溃,几乎总是出现内存不足错误。32mb并不是一个巨大的声明,但如果.NET正在分割内存,那么很可能如此大的连续分配没有按预期进行 有没有办法告诉垃圾收集器更具攻击性,或者对内存进行碎片整理(如果这是问题的话)?我意识到存在GC.Collect和GC.WaitForPendingFinalizers调用,我已经在代码中大量地使用

我有一个用于图像处理的应用程序,我发现自己通常分配4000x4000 ushort大小的数组,以及偶尔的浮点等。目前,该应用程序中的.NET framework可能会随机崩溃,几乎总是出现内存不足错误。32mb并不是一个巨大的声明,但如果.NET正在分割内存,那么很可能如此大的连续分配没有按预期进行

有没有办法告诉垃圾收集器更具攻击性,或者对内存进行碎片整理(如果这是问题的话)?我意识到存在GC.Collect和GC.WaitForPendingFinalizers调用,我已经在代码中大量地使用了它们,但仍然会出现错误。这可能是因为我调用了大量使用本机代码的dll例程,但我不确定。我已经看过C++代码,并确保我声明的任何内存都被删除,但我仍然会得到这些C崩溃,所以我确信它不存在。我想知道C++调用是否会干扰GC,使它留在内存中,因为它曾经与本地调用交互过,这是可能的吗?如果是,我可以关闭该功能吗

编辑:以下是一些会导致崩溃的非常具体的代码。根据,我不需要在这里处理BitmapSource对象。这是一个朴素的版本,里面没有GC.Collects。它通常在撤销过程的迭代4到10时崩溃。这段代码将替换空白WPF项目中的构造函数,因为我正在使用WPF。我之所以使用bitmapsource,是因为我在下面对@dthorpe的回答中解释了一些限制以及中列出的要求

公共部分类窗口1:窗口{
公共窗口1(){
初始化组件();
//试图创建OOM崩溃
//为此,模拟“图像”(ushort数组)的微小裁剪,然后撤消裁剪
int theRows=4000,当前行;
列内单位=4000,货币;
int theMaxChange=30;
int i;
List theList=new List();//撤消/重做堆栈中的图像列表
byte[]displayBuffer=null;//用作位图源的缓冲区
BitmapSource theSource=null;
对于(i=0;i=0;i--){
displayBuffer=新字节[theList[i]。长度];
source=BitmapSource.Create((列-i),(列-i),
96,96,PixelFormats.Gray8,null,displayBuffer,
((列-i)*PixelFormats.Gray8.BitsPerPixel+7)/8);
System.Console.WriteLine(“必须撤消更改”+i.ToString());
系统线程线程睡眠(100);
}
}
}
现在,如果我显式地调用垃圾收集器,我必须将整个代码包装在一个外部循环中,以导致OOM崩溃。对我来说,这往往发生在x=50左右:

public partial class Window1 : Window {
    public Window1() {
        InitializeComponent();
        //Attempts to create an OOM crash
        //to do so, mimic minute croppings of an 'image' (ushort array), and then undoing the crops
        for (int x = 0; x < 1000; x++){
            int theRows = 4000, currRows;
            int theColumns = 4000, currCols;
            int theMaxChange = 30;
            int i;
            List<ushort[]> theList = new List<ushort[]>();//the list of images in the undo/redo stack
            byte[] displayBuffer = null;//the buffer used as a bitmap source
            BitmapSource theSource = null;
            for (i = 0; i < theMaxChange; i++) {
                currRows = theRows - i;
                currCols = theColumns - i;
                theList.Add(new ushort[(theRows - i) * (theColumns - i)]);
                displayBuffer = new byte[theList[i].Length];
                theSource = BitmapSource.Create(currCols, currRows,
                        96, 96, PixelFormats.Gray8, null, displayBuffer,
                        (currCols * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
            }
            //should get here.  If not, then theMaxChange is too large.
            //Now, go back up the undo stack.
            for (i = theMaxChange - 1; i >= 0; i--) {
                displayBuffer = new byte[theList[i].Length];
                theSource = BitmapSource.Create((theColumns - i), (theRows - i),
                        96, 96, PixelFormats.Gray8, null, displayBuffer,
                        ((theColumns - i) * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
                GC.WaitForPendingFinalizers();//force gc to collect, because we're in scenario 2, lots of large random changes
                GC.Collect();
            }
            System.Console.WriteLine("Got to changelist " + x.ToString());
            System.Threading.Thread.Sleep(100);
        }
    }
}
公共部分类窗口1:窗口{
公共窗口1(){
初始化组件();
//试图创建OOM崩溃
//为此,模拟“图像”(ushort数组)的微小裁剪,然后撤消裁剪
对于(int x=0;x<1000;x++){
int theRows=4000,当前行;
列内单位=4000,货币;
int theMaxChange=30;
int i;
List theList=new List();//撤消/重做堆栈中的图像列表
byte[]displayBuffer=null;//用作位图源的缓冲区
BitmapSource theSource=null;
对于(i=0;i=0;i--){
displayBuffer=新字节[theList[i]。长度];
source=BitmapSource.Create((列-i),(列-i),
96,96,PixelFormats.Gray8,null,displayBuffer,
((列-i)*PixelFormats.Gray8.BitsPerPixel+7)/8);
GC.WaitForPendingFinalizers();//强制GC收集,因为我们在场景2中,有很多大的随机更改
GC.Collect();
}
System.Console.WriteLine(“转到变更列表”+x.ToString());
系统线程线程睡眠(100);
}
}
}
如果我在这两种情况下都处理不好内存,如果有什么我应该用分析器发现的,请告诉我。这是一个非常简单的程序

不幸的是,@Kevin的答案似乎是正确的——这是.NET中的一个bug,.NET如何处理大于85k的对象。这种情况让我觉得非常奇怪;Powerpoint可以用这种方式在.NET中重写吗
public partial class Window1 : Window {
    public Window1() {
        InitializeComponent();
        //Attempts to create an OOM crash
        //to do so, mimic minute croppings of an 'image' (ushort array), and then undoing the crops
        for (int x = 0; x < 1000; x++){
            int theRows = 4000, currRows;
            int theColumns = 4000, currCols;
            int theMaxChange = 30;
            int i;
            List<ushort[]> theList = new List<ushort[]>();//the list of images in the undo/redo stack
            byte[] displayBuffer = null;//the buffer used as a bitmap source
            BitmapSource theSource = null;
            for (i = 0; i < theMaxChange; i++) {
                currRows = theRows - i;
                currCols = theColumns - i;
                theList.Add(new ushort[(theRows - i) * (theColumns - i)]);
                displayBuffer = new byte[theList[i].Length];
                theSource = BitmapSource.Create(currCols, currRows,
                        96, 96, PixelFormats.Gray8, null, displayBuffer,
                        (currCols * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
            }
            //should get here.  If not, then theMaxChange is too large.
            //Now, go back up the undo stack.
            for (i = theMaxChange - 1; i >= 0; i--) {
                displayBuffer = new byte[theList[i].Length];
                theSource = BitmapSource.Create((theColumns - i), (theRows - i),
                        96, 96, PixelFormats.Gray8, null, displayBuffer,
                        ((theColumns - i) * PixelFormats.Gray8.BitsPerPixel + 7) / 8);
                GC.WaitForPendingFinalizers();//force gc to collect, because we're in scenario 2, lots of large random changes
                GC.Collect();
            }
            System.Console.WriteLine("Got to changelist " + x.ToString());
            System.Threading.Thread.Sleep(100);
        }
    }
}
using System.Runtime.InteropServices; 
....
public class anyname
{ 
....

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]

private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);

public static void alzheimer()
{
GC.Collect();
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
} 
public static void FlushMemory()
{
    Process prs = Process.GetCurrentProcess();
    prs.MinWorkingSet = (IntPtr)(300000);
}
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;