我故意在一个简单的 C# 程序中泄漏内存,以了解有关 .NET 如何管理这方面的更多信息。这是使用int[]数组完成的,每个数组的大小为 1000 万,每 100 毫秒声明一次。数组的元素不会被“触及”(如分配一个值),以免将数据带入进程的工作集中:
const int BlockSIZE = 10000000; // 10 million
const int noOfBlocks = 500;
int[][] intArray = new int[noOfBlocks][];
for (int k = 0; k < noOfBlocks; k++) {
intArray[k] = new int[BlockSIZE];
Console.WriteLine("Allocated (but not touched) for array {0}: {1} bytes", k, BlockSIZE);
System.Threading.Thread.Sleep(100);
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 VMMap(Mark Russinovich 构建的工具)来查看内存是如何分配的。该版本是最新版本(3.25,2018 年发布),因此它了解托管堆。
在具有 8 GB RAM 的 x64 Windows 10 计算机上使用 Visual Studio 2015 来编译和生成文件.exe。根据Platform target项目“构建”部分中的设置,可以看到与如何分配内存相关的不同结果,如下所示。
当 …
让我们考虑一些非常简单的C#代码:
static void Main(string[] args)
{
int i = 5;
string s = "ABC";
bool b = false;
}
Run Code Online (Sandbox Code Playgroud)
Jeffrey Richter的“ 通过C#进行CLR ”(第14章)指出,“ String类型是直接从Object派生的,使其成为引用类型,因此,String对象(其字符数组)始终存在于堆中,而不是在线程的堆叠 ”。
在书中的一个示例上也与上面的示例非常相似,它也涉及字符串:“ newobj IL指令构造了一个对象的新实例。但是,IL代码示例中没有newobj指令出现。相反,您看到了特殊的ldstr (负载字符串)IL指令,其通过使用从元数据得到的文字串构成一个字符串对象。这显示了公共语言运行库(CLR)不,事实上,具有构造文字串对象的一种特殊的方式。 “
查看IL代码,显然是这种情况(仅显示了相关部分):
[...]
.locals init (
[0] int32,
[1] string,
[2] bool
)
// (no C# code)
IL_0000: nop
// int num = 5;
IL_0001: ldc.i4.5
IL_0002: stloc.0
// string text = "ABC";
IL_0003: ldstr "ABC"
IL_0008: stloc.1
// bool flag = false;
[...]
Run Code Online (Sandbox Code Playgroud)
所述ldstrIL指令确保了 “ 的对象引用的字符串被压入堆栈 ”。这很有意义-字符串的实例保留在堆上,并且对该对象(其地址)的引用由变量存储在堆栈上。 …
假设在 x64 Windows 机器上使用最新版本的 Visual Studio 和 C# 并分配大量数据。
果然,在使用默认构建设置(如下图为 VS 2019 Preview 2.1)进行编译时,当您的进程达到 4 GB 时,您将耗尽用户虚拟地址空间。这是意料之中的,这里讨论了原因。
例如,分配本身可以通过创建几百个简单数组来完成,每个数组包含几百万个int元素。
我想了解的是为什么Any CPU/Prefer 32-bit选择 被选为默认构建选项。我也注意到,2015年VS具有相同的默认设置过了,最有可能的每一个出来,因为VS 11,如所描述的版本在这里。
通常被问到的问题是“什么是 AnyCPU...?” 并且已经反复回答(1 2 3 4 5),对定位的优点简要地接触x86/ x64/ Any CPU + Prefer 32-bit。但我还没有找到一个明确的答案,为什么被Any CPU + Prefer 32-bit选为 VS 中的默认设置。
查看默认情况下反对为 x64 构建的原因:
int),实际情况并非如此。当然,对数组本身的引用将是双倍的(8 个字节而不是 4 个字节),但仅此而已。根据“Windows Internals”一书(内存管理章节),页表结构本身的 PFN 条目在 x86 和 x64 架构上都是 64 位宽,只是有 3 …我在 .NET Core 上使用一些简单的 C# 代码来查看 Azure Functions 的执行情况。
\n\n用例是这样的:将 1000 万个 int 值添加到 ArrayList 作为 Azure 函数的一部分,并使用设置为 1 分钟的时间触发器来调用该函数。(我知道 ArrayList 已过时,不再使用,但我只是使用它来在堆上分配大量空间)。\n因此该函数的 C# 代码是这样的:
\n\nusing System.Collections;\n\npublic static void Run(TimerInfo myTimer, ILogger log)\n{\n ArrayList numbers = new ArrayList();\n Random random = new Random(1);\n int noNumbers = 10000000;\n for(int i=0;i<noNumbers;i++) {\n numbers.Add(random.Next(10));\n }\n\n log.LogInformation($"Created an ArrayList of {numbers.Count} elements");\n log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我检查了平台设置,发现这是 32 位的(我假设这是指 .NET Core 运行时为 32 位):
\n\n
在“桌面”环境中运行相同的示例代码,针对 …
考虑一个拥有 50 多个账户的 AWS 组织。每个账户都创建了一个角色,允许对 EC2 服务进行只读访问(名为“EC2ReadAccess”),并与主(/管理)账户建立信任关系。主账户中的单个 IAM 用户应用了一个策略,允许其在每个账户中担任该角色。
我希望能够使用唯一的 IAM 用户迭代所有帐户,以便检索所有 EC2 实例。我知道同时对所有帐户运行 CLI 命令是不可能的。撇开循环遍历每个账户中的区域不谈,这已经被广泛讨论了,是否有一个优雅的解决方案来做到这一点?
我想到的一个技巧是以编程方式构建文件credentials,以便它包含每个帐户的配置文件。每个配置文件依次“链接”到 IAM 用户的配置文件(如此处所述),并为每个条目更新角色内的账户 ID。下面是一个例子:
[user1]
aws_access_key_id=<key_id>
aws_secret_access_key=<secret_key>
[marketing]
role_arn = arn:aws:iam::123456789012:role/EC2ReadAccess
source_profile = user1
[dev]
role_arn = arn:aws:iam::234567890123:role/EC2ReadAccess
source_profile = user1
...
[prod]
role_arn = arn:aws:iam::345678901234:role/EC2ReadAccess
source_profile = user1
Run Code Online (Sandbox Code Playgroud)
运行 CLI 命令(在本例中aws ec2 describe-instances)可以附带--profile参数,以便循环显示credentials文件中存在的所有配置文件。该区域可以在另一个循环中循环。因此,预先以编程方式生成的要发出的命令列表可能类似于:
aws ec2 describe-instances --profile marketing --region us-east-1
aws ec2 describe-instances --profile marketing --region us-east-2
... …Run Code Online (Sandbox Code Playgroud)