zoukankan      html  css  js  c++  java
  • System.ArgumentException: 目标数组的长度不够。请检查 destIndex 和长度以及数组的下限

    扫码支付接口将要上线,近几天在优化系统性能。昨天把日志Helper类的日志记录改成了使用Queue<T>对象来实现异步处理。
    做了单元测试,并模拟多线程来测试后,发现正常。
    今天将站点部署到准生产环境,用loadrunner压测时,发现运行一段时间后报如下异常,并且导致iis进程挂掉:

    2017/2/16 11:50:08    [ClientPayAPI_115007438_1CD2C]酷宝获取二维码异常:System.ArgumentException: 目标数组的长度不够。请检查 destIndex 和长度以及数组的下限。
       在 System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
       在 System.Collections.Generic.Queue`1.SetCapacity(Int32 capacity)
       在 System.Collections.Generic.Queue`1.Enqueue(T item)
       在 CommonUtils.LogHelper.InputFile(String log, LogType logType)
       在 CommonUtils.LogHelper.Write(String logText)
       在 PaymentBLL.HttpMessageSignService.ValidPayRequestSign_New(String requestJson)
       在 PaymentPlatform.Kubao.QuickPay.ClientPayAPI.ExecFun_New(String request)
       在 PaymentPlatform.Kubao.QuickPay.ClientPayAPI.ProcessRequest(HttpContext context)

    本地再次模拟高并发测试,发现复现的几率很小。不过,无论如何,既然好在可以复现,就要解决。

    经查,Queue<T>以及List<T>这些泛型类不是线程安全的。在并发操作时,内部操作可能会出现问题。

    通过ILSpy(.Net 反编译软件,可以打开.NET 的exe和DLL等程序集,前提要求程序集未加密/未加壳/未做强度混淆),或者去微软官方(referencesource.microsoft.com,.net 已经开源了 )可以查看Enqueue方法的实现,可知并未控制并发。

    #region 程序集 mscorlib.dll, v4.0.0.0
    // C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETFrameworkv4.0mscorlib.dll
    #endregion
    
    // Adds item to the tail of the queue.
    //
    /// <include file='docQueue.uex' path='docs/doc[@for="Queue.Enqueue"]/*' />
    public void Enqueue(T item) {
        if (_size == _array.Length) {
            int newcapacity = (int)((long)_array.Length * (long)_GrowFactor / 100);
            if (newcapacity < _array.Length + _MinimumGrow) {
                newcapacity = _array.Length + _MinimumGrow;
            }
            SetCapacity(newcapacity);
        }
    
        _array[_tail] = item;
        _tail = (_tail + 1) % _array.Length;
        _size++;
        _version++;
    }

    对此问题,解决方案有2个:

    【方案一】入队时使用并发锁lock。

    【方案二】使用ConcurrentQueue<T>。ConcurrentQueue<T>表示线程安全的先进先出 (FIFO) 集合。这个类在.net类库的System.Collections.Concurrent下。System.Collections.Concurrent命名空间提供多个线程安全集合类。当有多个线程并发访问集合时,应使用这些类来代替System.Collections和System.Collections.Generic命名空间中的对应类型。

  • 相关阅读:
    LabVIEW(数据库连接)
    单片机之静态局部变量static
    LabVIEW(数据库自动编号)
    为什么大电容滤低频,小电容滤高频 ?(转载)
    电容、频率的一点小关系(项目有关)
    深入理解计算机系统 第三部分程序间的交互和通信
    深入理解计算机系统chapter9
    深入理解计算机系统chapter8
    深入理解计算机系统chapter7
    深入理解计算机系统chapter6
  • 原文地址:https://www.cnblogs.com/buguge/p/6410407.html
Copyright © 2011-2022 走看看