2010-11-23 3 views
2

Ich habe eine Website, die die folgenden Fehler zu werfen vor kurzem begonnen hat:ASP.NET SQL Server ConsumePreLoginHandshake nicht genügend Speicher vorhanden Ausnahme

A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 0 - Not enough memory is available to complete this request) 

Source: .Net SqlClient Data Provider 

Method: Void OnError(System.Data.SqlClient.SqlException, Boolean) 

Stack Trace: at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(Boolean encrypt, Boolean trustServerCert, Boolean& marsCapable) 
    at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, SqlConnection owningObject) 
    at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnection owningObject) 
    at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(String host, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, Int64 timerStart) 
    at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance) 
    at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance) 
    at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection) 
    at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options) 
    at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject) 
    at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject) 
    at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject) 
    at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) 
    at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 
    at System.Data.SqlClient.SqlConnection.Open() 
    at rbm.Portal.DAL.SiteManagerDB.GetTopLinks() 

Die GetTopLinks() ist definiert als:

public static List<Link> GetTopLinks() 
     { 
      List<Link> lLinks = new List<Link>(); 

      try 
      { 
       using(DbCommand dbCommand = GenericDataAccess.CreateCommand()) 
       { 
        dbCommand.CommandText = "RBM_V1_GetTopLinks"; 

        dbCommand.Connection.Open(); 

        using(DbDataReader dbReader = dbCommand.ExecuteReader()) 
        { 
         if(dbReader.HasRows) 
         { 
          int intId = dbReader.GetOrdinal("id"); 
          int intText = dbReader.GetOrdinal("text"); 
          int intLink = dbReader.GetOrdinal("link"); 

          while(dbReader.Read()) 
          { 
           lLinks.Add(FillTopLinkDataRecord(dbReader, intId, intText, intLink)); 
          } 
         } 

         dbReader.Close(); 
        } 

        dbCommand.Connection.Close(); 
       } 
      } 
      catch(Exception ex) 
      { 
       lLinks = null; 
       SiteManager.Instance.LogError(ex); 
      } 

      return lLinks; 
     } 

Die Die FillTopLinkDataRecord-Methode ist wie folgt definiert:

Die CreateCommand() ist definiert als :

public static DbCommand CreateCommand() 
     { 
      DbConnection dbConnection = CreateConnection(); 

      DbCommand dbCommand = dbConnection.CreateCommand(); 
      dbCommand.CommandType = CommandType.StoredProcedure; 

      return dbCommand; 
     } 

     public static DbConnection CreateConnection() 
     { 
      DbProviderFactory dbFactory = DbProviderFactories.GetFactory(RbmConfiguration.DbProvideName); 

      DbConnection dbConnection = dbFactory.CreateConnection(); 
      dbConnection.ConnectionString = RbmConfiguration.DbConnectionString; 

      return dbConnection; 
     } 

Die GetTopLinks wird aus diesem Code aufgerufen:

try 
       { 
        if(HttpContext.Current.Cache["TopLinks"] == null) 
        { 
         HttpContext.Current.Cache.Insert("TopLinks", SiteDB.GetTopLinks() ?? new List<Link>(), null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration); 
        } 

        return ((List<Link>)HttpContext.Current.Cache["TopLinks"]); 
       } 
       catch(Exception ex) 
       { 
        SiteManager.Instance.LogError(ex); 
        return null; 
       } 

Es gibt nicht viel mit diesem Code geändert hat, liest Daten aus der SQL-Server und erstellt ein Menü für den Standort.

Ich bin verwirrt, wo das Problem liegt, von dem Fehler würde ich annehmen, dass die SQL-Box das Problem ist, aber ein IISRESET auf dem IIS-Feld scheint das Problem für ca. 24 Stunden zu beheben. Die SQL-Box ist W2K8R2 (64bit) und hat 8 Kerne (2.99GHz), 8GB RAM und viel freien Speicherplatz (250+ GB). Die IIS-Box ist W2K8R2 (64bit) und hat 8 Kerne (2,66 GHz), 4 GB RAM und viel freien Speicherplatz (16 GB).

Hat jemand dieses Problem schon einmal gesehen? Ist das Problem mit SQL oder IIS? Jede Hilfe wäre willkommen.

Antwort

1

Es gibt ein paar Fragen, die ich zu sehen.

Erstens, ich sehe nicht, wo Sie Ihre Verbindungen zu entsorgen. Das ist wahrscheinlich das Hauptproblem hier und warum ein IISRESET das Problem vorübergehend behebt.

Verbindungen werden eventuell recycelt, aber wenn Ihre Last hoch genug ist (und sie muss nicht sehr hoch sein, damit dies kaputt geht), wird der Speicher für den Pool knapp werden.

Zweitens weiß ich eine Reihe von Entwickler ist wie zu abstrahieren und Createcreate, aber ich habe es nie in einer Weise umgesetzt gesehen, die langfristig funktioniert. Das erste, was ich tun würde, ist diese Methoden aus dem Weg zu räumen, da sie ohnehin nur aus einzelnen Codezeilen bestehen.

FYI letzte Woche fixierte ich eine Website, die fast genau die gleiche Code-Layout verwendet. Es brach mit verschiedenen Fehlern mit 30 Leuten, die die Seite benutzten. Sobald ich die generische Befehls- und Verbindungsinstanziierung los war und die Datenaufrufe ordnungsgemäß mit Anweisungen umgab, verschwanden die Fehler und unterstützen nun 100 Mal diese Zahl.

+0

Chris, vielen Dank für die prompte Antwort. Sie haben gesagt, dass die Verbindungen nicht geschlossen werden können, der Befehl jedoch in eine Verwendung eingeschlossen und explizit mit dbCommand.Connection.Close() geschlossen wird. Ist das nicht genug? Da in dieser App nicht viel DB-Code vorhanden ist, überarbeite ich die Methoden CreateCommand und CreateConnection wie vorgeschlagen. Interessant zu wissen, dass das generische Zeug auch Probleme verursachen kann. – markpirvine

+0

@markpirvine: Ich habe mich vertippt. Anschlüsse müssen ebenfalls entsorgt werden. – NotMe

+0

@markpirvine: Nur damit Sie wissen, alles, was IDisposable implementiert entweder in einer Mit-Klausel eingewickelt sein oder eine try..finally hat, der von dem Objekt verfügt. Die regelmäßige Speicherbereinigung kann diese Ressourcen nicht ändern, da die Klassen Wrapper für nicht verwalteten Code sind. – NotMe

Verwandte Themen