Unity中MoneyTruncate()触发栈溢出导致崩溃问题求助
问题概述
编写金额格式转换逻辑时,目标是将输入数值转换为带数量级单位的显示格式(如1000显示为1 thousand、1000000显示为1 million),运行时Unity抛出栈溢出错误后程序崩溃,报错位置为MoneyTruncate()方法内定义数组的代码行,错误提示:
The requested operation caused a stack overflow, MoneyTruncate() (at Assets/Scripts/Money.cs:60)
问题根因
栈溢出和后续崩溃和数组本身的定义没有关系,报错定位在数组初始化行,只是因为栈内存被耗尽时刚好执行到分配数组局部变量的步骤,具体问题点如下:
- 递归状态完全不传递:
i是方法内的局部变量,每次进入MoneyTruncate()都会被重置为0,递归调用时对i的自增、自减操作完全不会传递到下一层递归,导致每次递归的计算逻辑完全一致,无限触发递归调用,最终撑爆线程调用栈。 - 幂运算语法用错:C#中
^是异或位运算符,不是数学幂运算符号,代码中10 ^ (i * 3)的计算结果完全不是预期的10的3i次方,数值判断逻辑从根源上失效。 - 边界判断顺序错误+数组越界风险:
Numerals数组长度为4,合法索引范围是0~3,但代码把i>3的边界判断放在递归逻辑之后,还没等走到边界判断分支,就已经先触发递归,或者在i超出索引范围时直接访问数组成员触发异常。 - 缺少递归收敛保护:递归逻辑没有做i的合法范围前置校验,i为负数或者超过数组最大索引时仍然会继续递归,完全没有终止路径。
修正方案
把递归的状态变量i改为方法参数传递,保证每次递归的状态是连续的;替换错误的幂运算写法;把边界判断放在方法最前面保证递归一定会收敛;缓存UI组件避免重复调用GetComponent;建议用decimal类型存储金额规避浮点数精度问题。
修正后的参考代码:
// 编辑器里拖入关联的Text组件,提前缓存不要每次调用都取 [SerializeField] private Text _totalMoneyText; // 数级单位数组,可按需扩展 private readonly string[] _numerals = { "", "thousand", "million", "billion", "trillion" }; /// <summary> /// 外部调用的金额显示入口 /// </summary> /// <param name="totalMoney">要显示的总金额</param> public void UpdateMoneyDisplay(decimal totalMoney) { string formatStr = MoneyTruncate(totalMoney, 0); _totalMoneyText.text = $"${formatStr}"; } private string MoneyTruncate(decimal totalMoney, int unitIndex) { // 前置边界判断:已经到最高级单位,直接返回结果,终止递归 if (unitIndex >= _numerals.Length - 1) { decimal maxUnitVal = totalMoney / (decimal)Math.Pow(10, unitIndex * 3); return $"{maxUnitVal:0.00} {_numerals[unitIndex]}"; } decimal currentUnitVal = totalMoney / (decimal)Math.Pow(10, unitIndex * 3); decimal nextUnitVal = totalMoney / (decimal)Math.Pow(10, (unitIndex + 1) * 3); // 匹配到当前数级 if (currentUnitVal >= 1 && nextUnitVal < 1) { return $"{currentUnitVal:0.00} {_numerals[unitIndex]}"; } // 当前数级太大,降一级 else if (currentUnitVal < 1) { return MoneyTruncate(totalMoney, unitIndex - 1); } // 当前数级太小,升一级 else { return MoneyTruncate(totalMoney, unitIndex + 1); } }
- 补充说明:如果对性能要求更高,可以完全不用递归,直接用循环从低到高匹配数级即可,逻辑更直观也完全没有栈溢出风险。
内容的提问来源于stack exchange,提问作者Ignis196
相关产品推荐
相关产品推荐

