工作者这大致是这样
    bOK := GetQueuedCompletionStatus(hCompletion,dwTrans,DWORD(pPerHandle),POverlapped(pPerIO),WSA_INFINITE);
    if (bOK = FALSE) and (pPerIO <> nil) then
     ...释放资源
    if (dwTrans = 0) then
     ...释放资源
     case pPerIO.nOperationType of
      OP_RECV:
      ...接收拼包->解析->调用下面那段回复代码A
       OP_SEND:begin
        //***释放发送代码申请的内存  貌似这里有问题
        FreeMem(pPerIO^.DataBuff.buf, pPerIO^.DataBuff.len);          
        GlobalFreePtr(pPerIO);
      end;
--------------------
回复代码A
    //***申请发送缓冲区
    pPerIOData := GlobalAllocPtr(GPTR, SizeOf(PER_IO_DATA));
    pPerIOData.nOperationType := OP_SEND;
    pPerIOData^.DataBuff.buf := AllocMem(YQSHeaderSize + ms.Size);
    pPerIOData^.DataBuff.len := InitYQSHeader(pPerIOData^.DataBuff.buf, 2, 1, ms.Size);
    ...读取数据到缓冲
    if WSASend(AConn.Socket, @pPerIOData^.DataBuff, 1, @pPerIOData^.DataBuff.len, 0, @pPerIOData^.ol, nil) = SOCKET_ERROR then
    begin
      if (WSAGetLastError() <> ERROR_IO_PENDING) then
      begin  //出错释放资源
        if pPerIOData <> nil then
        begin
          FreeMem(pPerIOData^.DataBuff.buf, pPerIOData^.DataBuff.len);
          GlobalFreePtr(pPerIOData);
          exit;
        end;
      end;
    end;
测试环境:
50个C
C->S 每秒20字节请求  S->C回复30K数据
以上代码 我在做测试的时候 在只做了接收不然发送时 未出现问题  说明问题不是出在接收上  所以我只列了发送的代码
错误请问是
Free Heap block 1680040 modified at 1680074 after it was freed OutDbStr
也就是说 我在做了释放后 系统访问了我申请的内存
网上查了资料  有人说 第一次的到IOCP的时候 先不要释放  等结束  再发个标志让它释放  不过找不到例子不知道怎么解决
但我不知道错在哪 应该怎么改 高人指点
---------------------------------------------------
另外  我把发送代码改成 不用overlapped 也就是说不经过IOCP 运行了12小时以上 都没提示过这错 但这样又会取不到回复的字节量
                                                                                           //这里的@pPerIOData^.ol  ->nil  不经过IOCP
   if WSASend(AConn.Socket, @pPerIOData^.DataBuff, 1, @pPerIOData^.DataBuff.len, 0, nil, nil) = SOCKET_ERROR then
    begin
      if (WSAGetLastError() <> ERROR_IO_PENDING) then
      begin  //出错释放资源
        if pPerIOData <> nil then
        begin
          FreeMem(pPerIOData^.DataBuff.buf, pPerIOData^.DataBuff.len);
          GlobalFreePtr(pPerIOData);
          exit;
        end;
      end;
    end;
   //下面直接释放资源
    FreeMem(pPerIOData^.DataBuff.buf, pPerIOData^.DataBuff.len);
    GlobalFreePtr(pPerIOData);

解决方案 »

  1.   

    对pPerHandle做引用计数,当引用计数为0再释放.
      

  2.   

    一个支持引用计数的类:
    需要使用的时候调用Attach增加引用计数(如果返回的是Nil表示对象已经处于释放状态),成功之后调用Free释放引用计数,由于第一次创建的时候会自动增加一个引用计数,那么对于创建者就可以在需要的时候Free,这样子并不影响其它线程的使用,只要记得Attach(包括Create)和Free相对应即可(注:Delphi2007以下版本请把{$Region}和{$EndRegion}删除)
    unit UnitManagedObject;interfaceuses
        Windows
      ;
    type
      TManagedObject = class(TObject)
        {Management Properties}
          {$region}
        strict private
          FManagementCount  : Integer;      //对象引用计数
          {$endRegion}
        public
          {structor}
          {$region}
          constructor Create;
          {$endregion}
        public
          {Management}
          {$region}
          procedure Free;
          function Attach:TManagedObject;
          function Detach: Integer;
          {$endRegion}
      end;
    implementation{TManagedBaseObject}
    {$region}
      {structor}
      {$region}
      constructor TManagedObject.Create;
      begin
        Inherited Create;
        FManagementCount := 1;
      end;
      {$endregion}  {Management}
      {$region}
      function TManagedObject.Attach  : TManagedObject;
      begin
        Result := Nil;
        if InterlockedIncrement(FManagementCount) = 1 then
          begin
            InterlockedDecrement(FManagementCount);
            Exit;
          end;
        Result := self;
      end;  function TManagedObject.Detach  : Integer;
      begin
        Result := InterlockedDecrement(FManagementCount);
      end;  procedure TManagedObject.Free;
      begin
        if Detach>0 then
          Exit;
        Inherited;
      end;
      {$EndRegion}{$endRegion}
    end.
      

  3.   

    还有个问题不解  那就是 发送用的 单IO_Overlapped结构 是不是要重新申请  还是能直接用 接收绑定的单IO结构呢?
    可能这样讲不明白  就是:
    接收用一个 (单IO_Overlapped结构A)
    发送能不能也用 (单IO_Overlapped结构A) 来共用?   还是只能为发送重新申请一个空间 来用呢?
      

  4.   

    可以继续使用,既然是Per IO,那么当通知返回,实际上已经不再被使用了,所以可以进行使用或者释放