C#中分配内存实际上并不是分配内存
Allocating memory in C# is not actually allocating memory
当我声明一个新的字节数组时,内存使用量没有增加。
byte[] test = new[1024*100];
只有在我遍历每个字节后它才真正开始占用内存。
如何让它真正提交内存而不必先使用它?
我将其用作带有 try catch 块的测试,以查看它是否无法分配内存,从而告诉我我的应用程序已超出 ram,它不应尝试分配任何新对象。
编辑:因为我要分配的对象与垃圾收集器和堆栈一起使用,所以我不想使用 malloc 分配,因为它可能在那里成功,但在尝试分配新的托管对象时失败.
好吧,如果您真的想要映射所有内存,请重复数组并用零填充它。反正都是线性时间。为此使用 Array.Clear
。
C# 确实不是为这种内存优化而设计的。您唯一应该关心的资源是未损坏的资源。在 C# 中考虑剩余内存消耗的正确方法是 根本不考虑。老实说,在搜索这个问题之前,我不知道 C# 如何在数组声明期间处理内存分配,这就是重点,我没有使用高级抽象语言来关心这些东西。仅当您的工作应用程序遇到内存瓶颈并且需要优化时才有意义。
那里是一个stackalloc
operator, which you could maybe bend to your use, but it's an unsafe operator. Also there is GC.GetTotalMemory()
, which can show you the current memory usage (of managed objects), and Microsoft.VisualBasic.Devices.ComputerInfo.TotalPhysicalMemory
,它将为您提供机器的总RAM(不要介意名称中的VB,这是一个.NET Framework 方法,只需添加对 Microsoft.VisualBasic.Devices
) 的引用,因此使用它可以实现或多或少地了解是否有足够的内存供您分配数组的目标。
更新:
从 C# 7.2 开始,现在允许使用 stackalloc
而无需输入具有 Span<T>
和 ReadOnlySpan<T>
类型的 unsafe
上下文。但是,我无法确定 stackalloc
指令是否需要实际从堆栈分配,或者如果分配的缓冲区未使用,是否可以省略它,因此可能仍然需要实际遍历缓冲区以欺骗编译器认为需要分配。
如果你想让它分配所有的字节,你可以使用Array.Clear,它会用0填充所有的值
Array.Clear(test, 0, test.Length);
这个简单的控制台应用程序可让您监控内存使用情况,因为它已创建并使用 clear
class Program
{
static void Main(string[] args)
{
//Memory usage 7.1 MB
Console.WriteLine("Hit enter to allocate");
Console.ReadKey();
byte[] data = new byte[1024*1024]; //Memory still 7.1 MB
Console.WriteLine("Hit Enter to Fill with zeros!");
Console.ReadKey();
Array.Clear(data, 0, data.Length); //Memory now 8.1 MB
Console.WriteLine("1MB filled, hit enter to exit");
Console.ReadKey();
}
}
制作了一个函数,它将尝试实际分配我指定的内存(如果不可能则抛出异常而不是撒谎),如果成功将立即被垃圾收集器收集。
bool IsMemoryAvailable(int amount)
{
int size = (int)Math.Sqrt(amount) / 2;
try
{
using (Bitmap bmpTest = new Bitmap(size, size))
{
}
GC.Collect();
return true;
}
catch(Exception x)
{
return false;
}
}
如果迁移到 .NET 6,则可以利用新引入的 NativeMemory 方法使用 C API 分配本机内存:
using System.Runtime.InteropServices;
unsafe
{
byte* buffer = (byte*)NativeMemory.Alloc(200);
NativeMemory.Free(buffer);
}
当我声明一个新的字节数组时,内存使用量没有增加。
byte[] test = new[1024*100];
只有在我遍历每个字节后它才真正开始占用内存。
如何让它真正提交内存而不必先使用它?
我将其用作带有 try catch 块的测试,以查看它是否无法分配内存,从而告诉我我的应用程序已超出 ram,它不应尝试分配任何新对象。
编辑:因为我要分配的对象与垃圾收集器和堆栈一起使用,所以我不想使用 malloc 分配,因为它可能在那里成功,但在尝试分配新的托管对象时失败.
好吧,如果您真的想要映射所有内存,请重复数组并用零填充它。反正都是线性时间。为此使用 Array.Clear
。
C# 确实不是为这种内存优化而设计的。您唯一应该关心的资源是未损坏的资源。在 C# 中考虑剩余内存消耗的正确方法是 根本不考虑。老实说,在搜索这个问题之前,我不知道 C# 如何在数组声明期间处理内存分配,这就是重点,我没有使用高级抽象语言来关心这些东西。仅当您的工作应用程序遇到内存瓶颈并且需要优化时才有意义。
那里是一个stackalloc
operator, which you could maybe bend to your use, but it's an unsafe operator. Also there is GC.GetTotalMemory()
, which can show you the current memory usage (of managed objects), and Microsoft.VisualBasic.Devices.ComputerInfo.TotalPhysicalMemory
,它将为您提供机器的总RAM(不要介意名称中的VB,这是一个.NET Framework 方法,只需添加对 Microsoft.VisualBasic.Devices
) 的引用,因此使用它可以实现或多或少地了解是否有足够的内存供您分配数组的目标。
更新:
从 C# 7.2 开始,现在允许使用 stackalloc
而无需输入具有 Span<T>
和 ReadOnlySpan<T>
类型的 unsafe
上下文。但是,我无法确定 stackalloc
指令是否需要实际从堆栈分配,或者如果分配的缓冲区未使用,是否可以省略它,因此可能仍然需要实际遍历缓冲区以欺骗编译器认为需要分配。
如果你想让它分配所有的字节,你可以使用Array.Clear,它会用0填充所有的值
Array.Clear(test, 0, test.Length);
这个简单的控制台应用程序可让您监控内存使用情况,因为它已创建并使用 clear
class Program
{
static void Main(string[] args)
{
//Memory usage 7.1 MB
Console.WriteLine("Hit enter to allocate");
Console.ReadKey();
byte[] data = new byte[1024*1024]; //Memory still 7.1 MB
Console.WriteLine("Hit Enter to Fill with zeros!");
Console.ReadKey();
Array.Clear(data, 0, data.Length); //Memory now 8.1 MB
Console.WriteLine("1MB filled, hit enter to exit");
Console.ReadKey();
}
}
制作了一个函数,它将尝试实际分配我指定的内存(如果不可能则抛出异常而不是撒谎),如果成功将立即被垃圾收集器收集。
bool IsMemoryAvailable(int amount)
{
int size = (int)Math.Sqrt(amount) / 2;
try
{
using (Bitmap bmpTest = new Bitmap(size, size))
{
}
GC.Collect();
return true;
}
catch(Exception x)
{
return false;
}
}
如果迁移到 .NET 6,则可以利用新引入的 NativeMemory 方法使用 C API 分配本机内存:
using System.Runtime.InteropServices;
unsafe
{
byte* buffer = (byte*)NativeMemory.Alloc(200);
NativeMemory.Free(buffer);
}