首页 > 系统相关 >C# 使用 stackalloc 在栈上分配内存

C# 使用 stackalloc 在栈上分配内存

时间:2024-06-08 21:01:10浏览次数:33  
标签:C# int length 分配内存 stackalloc loot totalWeight lootDropSpan

stackalloc 官方文档

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/stackalloc

A stackalloc expression allocates a block of memory on the stack. A stack-allocated memory block created during the method execution is automatically discarded when that method returns. You can't explicitly free the memory allocated with stackalloc. A stack allocated memory block isn't subject to garbage collection and doesn't have to be pinned with a fixed statement.

stackalloc表达式会在栈上分配内存块。在函数运行时创建的栈上的内存块会在函数返回时自动销毁。你不能显式地释放stackalloc分配的内存。栈上内存块不受垃圾回收影响并且不需要使用fixed语句。

你可以将stackalloc表达式的结果赋值给以下类型的变量:

  • System.Span or System.ReadOnlySpan,
  • A pointer type
int length = 3;
Span<int> numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
    numbers[i] = i;
}

unsafe
{
    int length = 3;
    int* numbers = stackalloc int[length];
    for (var i = 0; i < length; i++)
    {
        numbers[i] = i;
    }
}

The amount of memory available on the stack is limited.
栈上的内存数量是有限的,避免在循环中使用stackalloc

The use of stackalloc automatically enables buffer overrun detection features in the common language runtime (CLR). If a buffer overrun is detected, the process is terminated as quickly as possible to minimize the chance that malicious code is executed.

实战应用

怪物掉落这种涉及资源分配的逻辑,必然需要放在服务端执行。而且执行频率和玩家杀怪速度相关。而击杀怪物基本上就是游戏核心逻辑的一部分,会被频繁执行。因此我们可以通过将怪物掉落相关的内存开销放在栈中来避免或者延迟垃圾回收的触发。 此处需要注意,stackalloc后面的类型需要是struct值类型。

    public void DropLoots(Monster monster)
    {
        int lootCount = GetLootCount(monster);

        //how to avoid stack overflow
        Span<MonsterLoot> lootResultSpan = stackalloc MonsterLoot[lootCount];
        Span<MonsterLoot> lootDropSpan = stackalloc MonsterLoot[monster.config.LootList.Count];
        for(int i = 0; i < monster.config.LootList.Count; i++) 
        {
            lootDropSpan[i] = monster.config.LootList[i];
        }
        

        for (int i = 0; i < lootCount; ++i)
        {
            var loot = Get1Loot(ref lootDropSpan);
            lootResultSpan[i] = loot;
        }
    }

    private MonsterLoot Get1Loot(ref Span<MonsterLoot> lootDropSpan)
    {
        int totalWeight = 0;
        foreach (var loot in lootDropSpan)
        {
            if (loot.DropCountLimit == 0)
                continue;

            totalWeight += loot.DropWeight;
        }


        float randomWeight = WildBoar.Random.Float01() * totalWeight;

        Debug.Log($"DropLoot totalWeight={totalWeight}  randomWeight={randomWeight}");

        int accumulateWeight = 0;

        for(int i = 0; i < lootDropSpan.Length; i++)
        {
            var loot = lootDropSpan[i];
            if (loot.DropCountLimit == 0)
                continue;

            accumulateWeight += loot.DropWeight;

            if (accumulateWeight >= randomWeight)
            {
                lootDropSpan[i].DropCountLimit--;
                return loot;
            }
        }

        throw new System.Exception("shouldnt reach here");
    }

标签:C#,int,length,分配内存,stackalloc,loot,totalWeight,lootDropSpan
From: https://www.cnblogs.com/dewxin/p/18238910

相关文章

  • C++ OpenCV 图像分类魔法:探索神奇的模型与代码
    ⭐️我叫忆_恒心,一名喜欢书写博客的研究生......
  • Cobalt Strike使用小记
    环境设置攻击机KaliLinux:172.24.4.7跳板机Windows10:172.24.4.22目标机Windows7:172.24.4.35Windows7作为目标机。启动CS服务端首先在Kali服务端启动CS,配置如下:IP:Kali的IP密码:demo(可以随意,但要记住)连接CS服务端在Windows10上启动CS客户端并连接......
  • C++20协程接口说明
    等待体的接口说明: boolawait_ready()表达了等待体对象是否准备就绪,返回false表示没有准备好,返回true表示准备好了,这个返回值决定了等待体的执行流程。 boolawait_suspend(Coro::coroutine_handle<Task::promise_type>)当await_ready返回fasle时,进入此函数执行,如果await_r......
  • 【python】OpenCV—Blob Detection(11)
    学习来自OpenCV基础(10)使用OpenCV进行Blob检测文章目录1、cv2.SimpleBlobDetector_create中文文档2、默认parameters3、配置parameters附录——cv2.drawKeypoints1、cv2.SimpleBlobDetector_create中文文档cv2.SimpleBlobDetector_create是OpenCV库中用于创......
  • C语言笔记第12篇:自定义类型(struct结构体)
    1、结构体类型的声明为什么要有自定义的结构类型呢?这是因为稍微复杂的类型,直接使用内置类型是不行的!比如:描述一个人或 一本书的价格、版号等信息。1.1结构的创建结构体是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量。1.1.1 结构的声明structt......
  • kvm链接克隆虚拟机迁移到openstack机器的实验
     总结如果是完整克隆的那种虚拟机,是可以直接在openstack使用的,如果镜像格式没问题的话。 因为kvm虚拟机大部分都是链接克隆出来的镜像,不可用直接复制使用,所以需要创建新的镜像文件 创建空盘:qemu-imgcreate-fqcow2mcwlink1-new.qcow250G将链接克隆镜像数据导入到空......
  • c语言分支循环语句
    与这相关的逻辑运算符和求素数的四种方法都在主页哦 if语句(三种形式)1.无else语句部分1)语法形式if(表达式)语句12)介绍如果表达式为真(成立),则语句执行;如果表达式为假(不成立),则语句不执行。注意:在c语言中,0表示真,非零表示假#include<stdio.h>intmain(){intn=0;scanf......
  • mysql order by后跟case when
    在SQL中,ORDERBY子句用于对查询结果进行排序。当在ORDERBY后面使用CASE语句时,它的原理是:根据CASE语句中定义的条件和结果,为查询结果集中的每一行生成一个临时的排序值。然后,根据这些排序值对结果集进行排序。具体来说,CASE语句在ORDERBY中的工作原理如下:   条件判断:CASE......
  • CF717G Underfail 题解
    题意:若干区间,区间有权值,选择一个子集,使得权值和尽量大并且每个点不被覆盖超过\(x\)次。\(n\le500\)思路:很神奇的一道题。我们考虑费用流,如果单纯的一边是区间一边是点的话其实并不好做,所以这道题我们直接建一排\(n+2\)个点,一个区间\(l,r\)就从\(l\)到\(r+1\)连......
  • 40.8K开源交流社区平台:Discourse
    Discourse:开放源代码,打造社区讨论的自由家园-精选真开源,释放新价值。概览Discourse是一个完全开源的社区平台,为那些希望完全控制自己网站运行方式和地点的组织和个人提供服务。经过十多年的实战考验,Discourse不断演进,满足用户对于强大社区平台的需求。它支持创建讨论话......