none
AccessViolationException錯誤類別 RRS feed

  • 問題

  • 各位前輩好:

    看了很多,嘗試很多但是一樣會有這問題,想請各位前輩幫忙釐清問題,我已經陷入迷思。

    開發工具VS2005

    資料庫Sybase15

    9個流程50多支程式

    錯誤訊息

    Exception type: AccessViolationException

    Exception message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

    我先說明來龍去脈,我們在幫人做網頁有關於資料相關查詢及繳費

    一開始在測試階段時有出現這錯誤的時候,然後我們工程師討論了許久也去找了相關文件,後來是找到說要把資料庫存取完後進行相關的關閉,後來就對全部的程式進行處理,後來這樣處理是可以處理掉AccessViolationException 的出現,但是在最後一個流程測試時(其他流程已經上線),一樣又出現這個訊息,程式處理如下

    AseCommand cmd = DB.m_conn.CreateCommand();
            cmd.CommandText = "bistrn..sp_AMSAG01E_001";
            cmd.CommandType = CommandType.StoredProcedure;
    
            cmd.Parameters.Add("@big", AseDbType.Char, 1);
            cmd.Parameters["@big"].Direction = ParameterDirection.Input;
            cmd.Parameters["@big"].Value = strBigno;
    
            cmd.Parameters.Add("@mid", AseDbType.Char, 2);
            cmd.Parameters["@mid"].Direction = ParameterDirection.Input;
            cmd.Parameters["@mid"].Value = strMidno;
    
            cmd.Parameters.Add("@useno", AseDbType.Char, 7);
            cmd.Parameters["@useno"].Direction = ParameterDirection.Input;
            cmd.Parameters["@useno"].Value = strUser;
     try
            {
              cmd.ExecuteNonQuery();
            }
            catch (System.Exception ex)
            {
              DB.DBclose();
              Response.Write(ex.Message.ToString().Trim());
              Response.End();         
            }
    
              strNewBig = cmd.Parameters["@newbig"].Value.ToString();
              strNewMid = cmd.Parameters["@newmid"].Value.ToString();
              strNewUser = cmd.Parameters["@newuseno"].Value.ToString();
    
              
              strCpy_mode = cmd.Parameters["@newcpy_mode"].Value.ToString();
    
              
              strCpy_dd = cmd.Parameters["@newcpy_dd"].Value.ToString();
    
              //關閉資料庫
              cmd.Dispose();
              DB.DBclose();
    
    
    

     

    本來是: public static string strConn = "Data Source='10.1.1.222';Port='2048';UID='';charset=big5;PWD='W';database='bistrn';Max Pool Size=200;Min Pool Size=20";

    後來改成: public static string strConn = "Data Source='10.1.1.222';Port='2048';UID='';charset=big5;PWD='W';database='bistrn';Max Pool Size=512;

    把Min Pool Size去掉Max Pool Size改成512

    這樣後來就測試就沒有出現,然後改完後今天上線更多人使用馬上就出現這個錯誤

    "嘗試讀取或寫入受保護的記憶體。這通常表示其他記憶體已損毀。"
    從本來的英文變成中文,後來又去看了資料我在別的論壇是有看到微軟發佈的更新是對於這問題的說明

    http://support.microsoft.com/kb/923028/en-us 

    但是看了又看,我想知道這問題,爬了很多文但是似乎是很多因素,走到這邊我實在很難判斷到底是主機問題還是程式問題,想請各位前輩指點迷津

     

    後來發現這問題實在是解決不了,上網找了很多資料大致上都是因為程式連DB造成的問題,或是DLL或EXE檔之間, DLL相依的版本不符的問題,或是微軟的問題後來整理一下經過推斷這支功能到連DB的處理都沒有去連DLL的動作,推論是DB後把連DB的寫法改變了
    2010年7月28日 上午 05:19

解答

  • public static AseConnection m_conn = new AseConnection(strConn);

    我看到這一行,想到一件事,這是不是表示整個程式都是使用同一個 Connection 物件在處理資料庫存取?

    即然是網頁就會有多人同時使用的可能,那就有可能某一支程式(A)在執行讀資料,結果跑到一半另一支程式(B)又呼叫,

    當 A 跑完的時候執行 Connection.Close(),但是對 B 而言變成執行到一半連線突然中斷。

    之前我遇過這樣的狀況,在 SQL 可以在連接字串中加上 "MultipleActiveResultSets=true",但是 Sybase 我不熟。

    • 已標示為解答 挨踢的人 2010年7月31日 上午 01:00
    2010年7月28日 上午 08:04
  • 大致看了一下你的程式碼,程式碼中有幾個問題需修改

    1.connection與command物件請不要使用static,你不用擔心這樣會不會導致連線數過多的問題,因為 ADO.Net本身有connection pool機制.
    connection的管理並非如你程式中的方式只要產生單一instance就能解決問題.

    2.所有存取資料有使用connection物件的部分建議修改底下方式
    SqlConnection con = new SqlConnection();
    try
    {
    ... //存取
    }
    catch
    {
    ...//例外處理
    }
    finally
    {
    con.close();
    }

    或是
    using(SqlConnection con = new SqlConnection())
    {
    try
    {
    ... //存取
    }
    catch
    {
    ...//例外處理
    }
    }

    3.如果本身需要將存取資料封裝成class,你的寫法有許多問題不是很完善.
    你可以參考SqlHelper這隻小程式,雖然已經是骨董了,但用於標準的ADO.Net還是不錯,你的程式的目的跟這隻小程式的用途雷同,可以參考後再依你的需求做些調整.
    http://www.koders.com/csharp/fidD4121D6E4BCA2DAB656D770903FECBFF7427D242.aspx?s=mdef%3Adataset

    • 已標示為解答 挨踢的人 2010年7月31日 上午 12:59
    2010年7月28日 上午 08:58
  • 應該是你把它寫靜態方法的關係, 如Magic Liao講的.

    因為你這樣宣告Connection

    public static AseConnection m_conn = new AseConnection(strConn);

    所以整個記憶體中只會存在一個m_conn, 我覺得你應該依programlin兄的建議把所有個static拿掉, 不要使用靜態的方法.

    而是為每個獨立的連線建立新的執行個體.讓每個user的連線能夠有獨立的記憶體空間運作, 就不會互相干擾了.

     


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    • 已標示為解答 挨踢的人 2010年7月31日 上午 01:00
    2010年7月29日 上午 05:20
    版主

所有回覆

  • 想問一下, 你程式碼中的 DB 是個類別還是某個類別產生的執行個體 ?

    我猜問題應該是出在DB的程式內容, 而不是你貼出來的Code.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    2010年7月28日 上午 05:44
    版主
  • 是調用DB這支程式,附上DB程式裡面的寫法

    /**
     * <p>Title: 資料庫連接函數</p>
     * <p>Description: 資料庫連接、查詢、更新資料處理</p>
     */
    
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using Sybase.Data.AseClient;
    using System.Data.SqlClient;
    
    namespace WBIS.Base.Fun
    {
      /// <summary>
      /// 資料庫連接及處理類,用來連接資料庫及讀取,更新資料庫處理
      /// </summary>
      public class DB
      {
    
        
        //2008 
        public static string strConn = "Data Source='10.1.1.222';Port='2048';UID='';charset=big5;PWD='W';database='bistrn';Max Pool Size=888";
    
        
    
        /// <summary>
        /// 資料庫處理之出錯提示信訊
        /// </summary>
        public static string strDBErrMag = "";
    
        ///<summary>
        ///連接資料庫對象
        ///</summary>
        public static AseConnection m_conn = new AseConnection(strConn);
    
        /// <summary>
        /// 創建一個命令
        /// </summary>
        public static AseCommand m_cmd = new AseCommand();
    
    
        /// <summary>
        /// 創建連接對象
        /// </summary>
        /// <returns></returns>
        public static AseConnection Conn()
        {
          
          if (strConn != "")
          {
            try
            {
              return new AseConnection(strConn);
            }
            catch (System.Exception ex)
            {
              strDBErrMag = "連接資料庫處理出錯:" + ex.Message.ToString();
              return null;
            }
          }
          else
            return null;
        }
    
    
        ///<summary>
        ///打開資料庫連接
        ///</summary>
        ///<remarks></remarks>
        public static Boolean Connect()
        {
          if (strConn == "")
          {
            return false;
          }
    
          try
          {
            //連接資料庫處理
            if (m_conn == null)
            {
              m_conn = new AseConnection(strConn);
              m_conn.Open();
              return true;
            }
            else if (m_conn.State == System.Data.ConnectionState.Closed)
            {
              m_conn.Open();
              return true;
            }
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "連接資料庫處理出錯:" + ex.Message.ToString();
            //funMessage.setStatusBarMag(strDBErrMag, true);
            return false;
          }
    
          return true;
        }
    
        ///<summary>
        ///關閉資料庫連接
        ///</summary>
        ///<remarks></remarks>
        public static Boolean DBclose()
        {
          try
          {
            //關閉資料庫之連接
            if (m_conn.State != System.Data.ConnectionState.Closed)
            {
              m_conn.Close();
              return true;
            }
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "關閉資料庫之連接出錯:" + ex.Message.ToString();
            //funMessage.setStatusBarMag(strDBErrMag, true);
            return false;
          }
    
          return false;
        }
    
        /// <summary>
        /// 查詢資料庫之資料,並返回資料集
        /// </summary>
        /// <param name="strSQL">查詢之SQL</param>
        /// <param name="strFillTalbeName">資料集名稱</param>
        /// <param name="DataSet">返回之DateSet資料</param>
        /// <returns>true 表示刪除成功,false刪除失敗</returns>
        public static Boolean RunDataToDs(string strSQL, string strFillTalbeName, System.Data.DataSet DataSet)
        {
          //初始化資料的值
          strDBErrMag = "";
    
          AseConnection conn = Conn();
    
          if (conn == null)
            return false;
    
    
          try
          {
            //打開連接
            conn.Open();
    
            //設定查詢之連接,並進行查詢
    
            AseDataAdapter DA = new AseDataAdapter(strSQL, conn);
            DA.SelectCommand.CommandText = strSQL;
            DA.SelectCommand.CommandTimeout = 9000;
    
            DA.Fill(DataSet, strFillTalbeName);
    
            DA.Dispose();
            conn.Close();
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "SQL查詢出錯:" + ex.Message.ToString().Trim();
            conn.Close();
            //funMessage.setStatusBarMag(strDBErrMag, true);
            return false;
          }
    
          return true;
        }
    
        /// <summary>
        /// 更新資料資料庫的資料。true 表示刪除成功,false刪除失敗
        /// </summary>
        /// <param name="strSQL">更新的SQL</param>
        /// <returns>true 表示刪除成功,false刪除失敗</returns>
        public static Boolean UpdateDataSQL(string strSQL)
        {
          //初始化資料的值
          strDBErrMag = "";
    
          AseConnection conn = Conn();
    
          if (conn == null)
            return false;
    
          try
          {
            conn.Open();
    
            //進行程式更新到資料表 
            AseCommand cmd = conn.CreateCommand ();
            cmd.CommandText = strSQL;
            //cmd.ExecuteReader();
            cmd.ExecuteNonQuery();
            //cmd.ExecuteNonQuery ();
    
            cmd.Dispose ();
            conn.Dispose();
    
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "更新SQL出錯:" + ex.Message.ToString().Trim();
            //funMessage.setStatusBarMag(strDBErrMag, true);
            conn.Dispose();
            return false;
          }
    
          return true;
        }
    
        /// <summary>
        /// 調用SP過程
        /// </summary>
        /// <param name="strSP">SP名稱</param>
        /// <returns></returns>
        public static Boolean setExecSP(string strSP)
        {
          if (Connect() == false)
          {
            return false;
          }
    
          try
          {
            m_cmd = new AseCommand();//創建一個命令
    
            m_cmd.Connection = m_conn;//指定命令連接
            m_cmd.CommandType = CommandType.StoredProcedure;//指定命令類型
            m_cmd.CommandText = strSP;//指定當前值行SP過程
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "更新SQL出錯:" + ex.Message.ToString().Trim();
            return false;
          }
    
          return true;
        }
    
        /// <summary>
        /// 
        /// </summary>
        /// <param name="strFillTalbeName"></param>
        /// <param name="DataSet"></param>
        /// <returns></returns>
        public static Boolean RunDataToDs(string strFillTalbeName, System.Data.DataSet DataSet)
        {
    
          try
          {
            AseDataAdapter da = new AseDataAdapter();
            da.SelectCommand = m_cmd;
            da.Fill(DataSet, strFillTalbeName);
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "更新SQL出錯:" + ex.Message.ToString().Trim();
            return false;
          }
    
          return true;
        }
    
      }
    
    }
    
    2010年7月28日 上午 06:33
  • Hi,

     

    在您的程式碼中沒有很明確看到connection.open這個呼叫, 不知道您在程式碼中有沒有處理這段?

    根據SyBase線上的說明 ,有可能拋出問題的地方:

    max pool size

    You can restrict the connection pool not to grow more than the specified max pool size. The provider will throw an AseException on AseConnection.Open() if this limit is reached

    No

    100

    min pool size

    You can force the provider to close connections to ASE so that total number of open connections hover around min pool size. The provider closes the connection on AseConnection.Close() if the number of connections in the pool are equal to min pool size

    No

    20

     

     

    供您參考看看.

     

     

     

     

    rgs,

    Lolota


    Tech.Days Taiwan 2010 即將於 9/28-9/30 隆重展開!我們很榮幸向您推薦此微軟年度重量級的技術盛會

    2010年7月28日 上午 06:36
  • 有打開,不好意思前面貼的不完整,補上前面相關處理部份

               //調用SP
                if (DB.Connect() == false)
                {
                    Response.Write("<Script Language='JavaScript'>alert('" + DB.strDBErrMag + "');history.back();</Script>");
                    Response.End();
                }
                else
                {
                    AseCommand cmd = DB.m_conn.CreateCommand();
                    cmd.CommandText = "bistrn..sp_AMSAG01E_001";
                    cmd.CommandType = CommandType.StoredProcedure;

    連接到DB這支程式這一段進行相關處理

     ///<summary>
        ///打開資料庫連接
        ///</summary>
        ///<remarks></remarks>
        public static Boolean Connect()
        {
          if (strConn == "")
          {
            return false;
          }

          try
          {
            //連接資料庫處理
            if (m_conn == null)
            {
              m_conn = new AseConnection(strConn);
              m_conn.Open();
              return true;
            }
            else if (m_conn.State == System.Data.ConnectionState.Closed)
            {
              m_conn.Open();
              return true;
            }
          }
          catch (System.Exception ex)
          {
            strDBErrMag = "連接資料庫處理出錯:" + ex.Message.ToString();
            //funMessage.setStatusBarMag(strDBErrMag, true);
            return false;
          }

          return true;
        }

    2010年7月28日 上午 07:26
  • public static AseConnection m_conn = new AseConnection(strConn);

    我看到這一行,想到一件事,這是不是表示整個程式都是使用同一個 Connection 物件在處理資料庫存取?

    即然是網頁就會有多人同時使用的可能,那就有可能某一支程式(A)在執行讀資料,結果跑到一半另一支程式(B)又呼叫,

    當 A 跑完的時候執行 Connection.Close(),但是對 B 而言變成執行到一半連線突然中斷。

    之前我遇過這樣的狀況,在 SQL 可以在連接字串中加上 "MultipleActiveResultSets=true",但是 Sybase 我不熟。

    • 已標示為解答 挨踢的人 2010年7月31日 上午 01:00
    2010年7月28日 上午 08:04
  • 大致看了一下你的程式碼,程式碼中有幾個問題需修改

    1.connection與command物件請不要使用static,你不用擔心這樣會不會導致連線數過多的問題,因為 ADO.Net本身有connection pool機制.
    connection的管理並非如你程式中的方式只要產生單一instance就能解決問題.

    2.所有存取資料有使用connection物件的部分建議修改底下方式
    SqlConnection con = new SqlConnection();
    try
    {
    ... //存取
    }
    catch
    {
    ...//例外處理
    }
    finally
    {
    con.close();
    }

    或是
    using(SqlConnection con = new SqlConnection())
    {
    try
    {
    ... //存取
    }
    catch
    {
    ...//例外處理
    }
    }

    3.如果本身需要將存取資料封裝成class,你的寫法有許多問題不是很完善.
    你可以參考SqlHelper這隻小程式,雖然已經是骨董了,但用於標準的ADO.Net還是不錯,你的程式的目的跟這隻小程式的用途雷同,可以參考後再依你的需求做些調整.
    http://www.koders.com/csharp/fidD4121D6E4BCA2DAB656D770903FECBFF7427D242.aspx?s=mdef%3Adataset

    • 已標示為解答 挨踢的人 2010年7月31日 上午 12:59
    2010年7月28日 上午 08:58
  • public static AseConnection m_conn = new AseConnection(strConn);

    我看到這一行,想到一件事,這是不是表示整個程式都是使用同一個 Connection 物件在處理資料庫存取?

    即然是網頁就會有多人同時使用的可能,那就有可能某一支程式(A)在執行讀資料,結果跑到一半另一支程式(B)又呼叫,

    當 A 跑完的時候執行 Connection.Close(),但是對 B 而言變成執行到一半連線突然中斷。

    之前我遇過這樣的狀況,在 SQL 可以在連接字串中加上 "MultipleActiveResultSets=true",但是 Sybase 我不熟。

    的確,這是我沒思考到的地方,謝謝前輩的指引,後來我有去找sybase的SQL相關語法是沒有找到,但是是有看到有關於MultipleActiveResultSets的介紹及使用方式

    後來我將程式碼改成

    public static string strConn = "Data Source='10.1.1.222';Port='2048';UID='';charset=big5;PWD='W';database='bistrn';MultipleActiveResultSets=true;Max Pool Size=888";
    這種方式,測試之後是沒有出現錯誤訊息,也不知道是不是正確的寫法,還要正式更新給客戶才會知道....

    2010年7月28日 上午 10:46
  • 昨天後來到晚上測試,Magic_Liao 大大說的對

    因為如果同時兩部電腦一起連同一的網頁的查詢功能,時間一模一樣就會出現那錯誤訊息。

    後來昨天晚上是有跟別的同事討論到曾經他說他另一個案子有一個狀況,當時在做網頁的壓力測試500戶同時進行然後怎麼測都很慢,後來推斷狀況之後詢問oracle這方面技術,才發現是因為就算有500戶進去連到資料庫還是一樣只有一個線程,才在與oracle詢問解決方式之後在程式裡面有相對處理pooling。

    當時推斷原因是當你在New Connect  的時候 應該有一個線程給你用,然後當下一個進來就將對在給他一條線程,但是程式看起來就是當第一條關了你後面第二條還沒跑完就跟著關掉。

    程式也有依據programlin提供的方式將static處理掉。

    今天早上有跟sybase講過這狀況,把情形說給他們聽,他們是回覆說如果你用AP server連接方式有可能會造成500戶只有對一個連接數的狀況就會有這問題

    但是如果你是用ADO.net連接方式就是你連多少戶就有多少個連接數。

    聽完之後去找了相關資料,看到了以下這兩種連接方式

    AP 連接語句   Data

    Source='192.168.0.100';Port='8000';UID='d';PWD='';Database='bisbas';charset=big5;PacketSize=1;Default Length For Long Data=3072

    ADO.net 連接對象  Sybase.Data.AseClient.AseConnection

    不過總覺得AP連接方式或ADO.NET連接方式,不管是哪種應該都可以克服這狀況巴,不知道各位前輩有什麼高見???

    • 已標示為解答 挨踢的人 2010年7月31日 上午 12:59
    • 已取消標示為解答 挨踢的人 2010年7月31日 上午 12:59
    2010年7月29日 上午 05:09
  • 應該是你把它寫靜態方法的關係, 如Magic Liao講的.

    因為你這樣宣告Connection

    public static AseConnection m_conn = new AseConnection(strConn);

    所以整個記憶體中只會存在一個m_conn, 我覺得你應該依programlin兄的建議把所有個static拿掉, 不要使用靜態的方法.

    而是為每個獨立的連線建立新的執行個體.讓每個user的連線能夠有獨立的記憶體空間運作, 就不會互相干擾了.

     


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    • 已標示為解答 挨踢的人 2010年7月31日 上午 01:00
    2010年7月29日 上午 05:20
    版主
  • 應該是你把它寫靜態方法的關係, 如Magic Liao講的.

    因為你這樣宣告Connection

    public static AseConnection m_conn = new AseConnection(strConn);

    所以整個記憶體中只會存在一個m_conn, 我覺得你應該依programlin兄的建議把所有個static拿掉, 不要使用靜態的方法.

    而是為每個獨立的連線建立新的執行個體.讓每個user的連線能夠有獨立的記憶體空間運作, 就不會互相干擾了.

     


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。


    呼.....終於謝謝各位大大的建議,前天晚上把所DB部分重新改寫把static部分去掉改成需要在new一個使用。

    後來昨天實際測試一天,就沒有出現錯誤的訊息,真是太好了。

    2010年7月31日 上午 12:59