You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity3D中不使用unsafe与fixed关键字向字节数组写入值的高效方案

在Unity禁用unsafe时,高效将变量写入字节数组指定位置的方案

这个问题在Unity开发里挺常见的——毕竟unsafe代码在很多项目里是被禁用的,尤其是要发布到某些平台的时候。你提到的BinaryReader/BinaryWriter确实能用,但咱们得聊聊更高效的方案,毕竟Unity对GC和性能挺敏感的:

先说说BinaryReader/BinaryWriter的可行性

它们确实可以实现需求,但不是性能最优的选择。因为这两个类依赖Stream接口,你需要把字节数组包装成MemoryStream来使用,会产生额外的对象分配和调用开销。如果只是偶尔写入单个值,倒也能用,但高频场景下会增加GC压力。示例代码如下:

int value = 3;
byte[] array = new byte[100];
int offset = 10;

using (var ms = new MemoryStream(array, offset, sizeof(int)))
using (var bw = new BinaryWriter(ms))
{
    bw.Write(value);
}

更高效的替代方案

1. 手动位运算(零分配,极致性能,兼容所有Unity版本)

直接通过位运算拆分int的每个字节,写入数组指定位置。这种方法完全没有额外内存分配,性能和unsafe代码几乎一致,适合对性能要求极高的场景(比如帧循环里的高频数据处理)。

int value = 3;
byte[] array = new byte[100];
int offset = 10;

// 小端模式(x86/x64系统默认,Unity绝大多数场景用这个)
array[offset] = (byte)(value & 0xFF);
array[offset + 1] = (byte)((value >> 8) & 0xFF);
array[offset + 2] = (byte)((value >> 16) & 0xFF);
array[offset + 3] = (byte)((value >> 24) & 0xFF);

// 如果需要大端模式(比如网络协议场景),调整字节顺序即可
// array[offset + 3] = (byte)(value & 0xFF);
// array[offset + 2] = (byte)((value >> 8) & 0xFF);
// array[offset + 1] = (byte)((value >> 16) & 0xFF);
// array[offset] = (byte)((value >> 24) & 0xFF);

2. MemoryMarshal.Write(零分配,代码简洁,Unity 2020+支持)

如果你的Unity项目版本在2020及以上(引入了较新的.NET Runtime),MemoryMarshal.Write是最优解——它通过Span<T>直接操作数组内存,既没有unsafe代码,也没有额外分配,代码还很简洁。

int value = 3;
byte[] array = new byte[100];
int offset = 10;

// 获取从offset开始、长度为int字节数的Span<byte>
Span<byte> targetSpan = array.AsSpan(offset, sizeof(int));
// 直接将int值写入Span对应的内存区域
MemoryMarshal.Write(targetSpan, ref value);

这个方法内部逻辑和unsafe的内存操作一致,但完全符合Unity的代码规范,没有任何安全风险。

3. BitConverter + Buffer.BlockCopy(代码简单,适合低频场景)

BitConverter.GetBytes可以快速把int转成byte数组,再用Buffer.BlockCopy复制到目标数组的指定位置。缺点是BitConverter.GetBytes会每次分配一个4字节的数组,高频使用会产生GC垃圾。如果要优化,可以提前缓存一个byte数组重复使用。

普通版(有分配):

int value = 3;
byte[] array = new byte[100];
int offset = 10;

byte[] intBytes = BitConverter.GetBytes(value);
Buffer.BlockCopy(intBytes, 0, array, offset, intBytes.Length);

优化版(复用缓存,减少分配):

// 提前在类里初始化缓存数组,全局复用
private static readonly byte[] _intCacheBuffer = new byte[4];

// 使用时
int value = 3;
byte[] array = new byte[100];
int offset = 10;

// 先把int值写入缓存(这里可以用手动位运算避免BitConverter的分配)
_intCacheBuffer[0] = (byte)(value & 0xFF);
_intCacheBuffer[1] = (byte)((value >> 8) & 0xFF);
_intCacheBuffer[2] = (byte)((value >> 16) & 0xFF);
_intCacheBuffer[3] = (byte)((value >> 24) & 0xFF);

// 再复制到目标数组
Buffer.BlockCopy(_intCacheBuffer, 0, array, offset, _intCacheBuffer.Length);

总结选择建议

  • 追求极致性能且要兼容所有Unity版本:选手动位运算
  • Unity版本≥2020,想要代码简洁又高效:选MemoryMarshal.Write
  • 低频使用、代码简单优先:选BitConverter + Buffer.BlockCopy
  • 已经在使用BinaryReader/BinaryWriter处理序列化逻辑:可以顺便用它们,但单独写单个值不推荐

内容的提问来源于stack exchange,提问作者Hyunjik Bae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:47:05