线上网站Session存储的数组运行一段时间后自动归零,如何排查问题
线上Session存储数组自动重置为0的问题原因
核心问题根源来自Session存储模式的环境差异,加上代码写法的固有缺陷
两类环境的Session机制差异是直接触发原因
- 本地开发环境默认采用
InProc(进程内)会话存储模式,所有Session对象直接存在IIS工作进程的托管内存中。通过Session["array"]取出的数组是原对象的内存引用,代码中对array[2]的修改直接作用于内存中的原对象,不需要额外回写就能生效,因此本地运行无异常。 - 线上正式环境一旦满足以下任意一种场景,就会出现值重置的表象:
- 如果线上配置了
StateServer、SQLServer等非进程内会话存储模式:Session存储时会对对象做序列化处理,取出对象时会反序列化生成一个全新的临时副本。代码中对array[2]的修改仅作用于这个临时副本,没有显式回写到Session存储源中,下次请求读取Session时拿到的依然是最初初始化的、全为0的数组,看起来就像值被自动重置。 - 就算线上依然是单机
InProc模式:只要应用程序池触发自动回收(默认29小时定时回收、内存占用阈值触发、空闲超时回收),工作进程重启后所有内存中的Session会被清空。此时代码中if (Session["array"] == null)的判断会命中,重新初始化一个全为0的新数组,用户侧就会感知到之前存储的值全部被重置。
- 如果线上配置了
代码逻辑的固有缺陷
当前写法仅适配纯进程内引用传递的场景,存在明显的逻辑漏洞:
// 非InProc模式下完全不生效的错误写法 int[] array = (int[])Session["array"]; array[2]++; // 修改的是反序列化生成的临时副本,没有同步到Session存储
只要会话存储不是直接返回内存原引用,这种修改就不会持久化到Session中,必须在修改完成后显式回写才能兼容所有Session模式:
// 兼容所有Session存储模式的正确写法 int[] array = (int[])Session["array"]; array[2]++; Session["array"] = array; // 显式触发Session存储更新
其他容易触发重置的线上场景
- 线上多实例部署做负载均衡时,如果没有配置粘性会话(会话亲和性),用户请求会被随机分发到不同服务器实例上,各实例的Session相互独立。请求落到未存储过数组的实例上时,就会触发初始化逻辑生成全0的新数组。
- 线上Session超时配置过短,用户操作间隔超过超时阈值后Session会被自动清空,后续操作时触发重新初始化,也会出现值被重置为0的效果。
内容的提问来源于stack exchange,提问作者user13350003
相关产品推荐
相关产品推荐

