在 Jet ODBC 驱动程序与 SQL_NUMERIC 或 SQL_C_BINARY 数据中的 FIX: 内存泄漏

文章翻译 文章翻译
文章编号: 273772 - 查看本文应用于的产品
展开全部 | 关闭全部

本文内容

症状

Jet ODBC 驱动程序中调用 SQLBindParameter 函数和时,将绑定到一个 SQL 数据类型 SQL_NUMERIC 或 SQL_C_BINARY 绑定到 SQL_WCHAR 时,就会发生内存泄漏。

如果您要监视进程的专用字节数使用性能监视器 (PerfMon),您看到一个逐步但稳定的内存增加,和语句或连接关闭时,不会释放内存。

原因

缓冲区 Jet ODBC 驱动程序中用于帮助将 ODBC 参数数据类型转换为 Jet 数据库引擎的本机数据类型。这些缓冲区是通过指针作为参数说明符 (IPDs) 的一部分维护的语句句柄引用的。

通常情况下,该代码检查指针已经引用了有效的内存的缓冲区,然后再重新使用缓冲区,如果存在,请参阅。但是,绑定一个 SQL_NUMERIC 数据类型时,或在绑定到 SQL_WCHAR SQL_C_BINARY 时,分配新的内存并将其分配给该指针,而不首先,对它进行检查和以前的值将被覆盖。

解决方案

最新的服务包,Windows 2000 和 MDAC 2.5 中解决此问题。
  • 若要解决此问题,获得最新的 service pack,对于 Windows 2000。有关更多的信息请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
    260910如何获取最新的 Windows 2000 服务软件包
  • 若要解决此问题,获得最新的 service pack,对于 Microsoft 数据访问组件 2.5。有关更多的信息请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
    293312信息: 如何获取最新 MDAC 2.5 服务包
此修复程序的英文版应具有以下文件属性或更高版本:
   Date        Version       Size              File name    
   ---------------------------------------------------------------------
   09/13/00    4.0.5708.0    270,608 bytes    Odbcjt32.dll
   09/14/00    1.10.101.0    295,696 bytes    Q273772_W2K_SP2_x86_en.EXE
				
: 此修补程序需要 Microsoft 数据访问组件 (MDAC) 2.5 服务包 1 (SP1) 或更高版本的其他文件上的依赖项由于引入了 MDAC 2.5 sp1。尚无可用您可以将其应用于 MDAC 2.5 直接的修补程序。

在 Microsoft Windows 2000 平台上安装此修补程序,运行修补安装程序程序包 (Q273772_W2K_SP2_x86_en.EXE)。尽管此修补程序本身不是依赖于平台的修补安装程序程序包旨在仅在 Windows 2000 平台上运行,并将不能在 Microsoft Windows NT 4.0、 Microsoft Windows 95 或 Microsoft Windows 98 平台上运行。MDAC 包含系统文件保护文件,您仅可通过在 Windows 2000 上一个经过数字签名的修补程序的安装程序来替换这些文件。以便您可以将该文件复制到 Windows NT 4.0,Windows 95 或 Windows 98 的平台的直接,还提供独立的修补程序文件。


解决方法

没有关于此问题的解决方法。

状态

Microsoft 已经确认这是在本文开头列出的 Microsoft 产品中的问题。Microsoft 数据访问组件 2.5 Service Pack 2 和 Microsoft Windows 2000 Service Pack 2 中,第一次已得到纠正此问题。

更多信息

如果您检查定期在进程运行时进程的内存,您将看到越来越多的 0x100000 (1048576) 字节分配。如果该进程将继续运行,最终内存不足,无法运行,并停止响应 (挂起) 或过程失败。

重现行为的步骤

  1. 复制到 Microsoft Visual c + + 控制台应用程序下面的代码,然后编译代码。请注意您可能需要更改数据源名称、 用户 id 和密码。
    #include <windows.h>
    #include <sql.h>
    #include <sqlext.h>
    #include <tchar.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    
    #define LEAK_NUMERIC 1		//Use this to determine NUMERIC or BINARY leak
    
    
    void HandleError(SQLHANDLE	hHandle, SQLSMALLINT hType, RETCODE RetCode)
    {
    	SQLSMALLINT	iRec = 0;
    	SQLINTEGER	iError;
    	TCHAR		szMessage[1000];
    	TCHAR		szState[SQL_SQLSTATE_SIZE];
    
    
    	if (RetCode == SQL_INVALID_HANDLE)
    	{
    		fprintf(stderr,"Invalid handle!\n");
    		return;
    	}
    
    	while (SQLGetDiagRec(hType,
    			 hHandle,
    			 ++iRec,
    			 (SQLCHAR *)szState,
    			 &iError,
    			 (SQLCHAR *)szMessage,
    			 (SQLSMALLINT)(sizeof(szMessage) / sizeof(TCHAR)),
    			 (SQLSMALLINT *)NULL) == SQL_SUCCESS)
    	{
    		fprintf(stderr,TEXT("[%5.5s] %s (%d)\n"),szState,szMessage,iError);
    	}
    
    }
    
    
    char* szConnStringIn = "Driver={Microsoft Access Driver (*.mdb)};DBQ=E:\\JetLeak\\TestDatabase.mdb";
    char* szDropTable = "DROP TABLE LeakTable";
    //char* szInsertStatement = "INSERT INTO LeakTable VALUES (?)";
    char* szSelectStatement = "SELECT * FROM LeakTable WHERE val1 = ?";
    const int nParamCount = 1; 
    
    #if LEAK_NUMERIC
    char* szCreateTable = "CREATE TABLE LeakTable (val1 long)";
    #else
    char* szCreateTable = "CREATE TABLE LeakTable (val1 varchar(10))";
    #endif
    
    
    
    void main(int argc, char* argv[])
    {
    	SQLHENV henv;
    	SQLHDBC hdbc;
    	SQLHSTMT hstmt;
    	SQLRETURN nstatus;
    
    	char szConnStringOut[1024];
    	SQLSMALLINT cbConnOut;
    	SQLINTEGER status[nParamCount];
    
    #if LEAK_NUMERIC
    	SQLCHAR szParam[nParamCount][10] = {"12345"};
    #else
    	BYTE szParam[nParamCount][10] = {0x31,0x33,0x34,0x39};
    #endif
        
    	//Not checking the return codes in some cases for clarity.
    	
    	nstatus = SQLAllocHandle(SQL_HANDLE_ENV,NULL,&henv);
    	nstatus = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER) SQL_OV_ODBC3,0);
    	nstatus = SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);
    
    	nstatus = SQLDriverConnect(hdbc,
    			NULL,
    			(SQLCHAR*) szConnStringIn,
    			SQL_NTS,
    			(SQLCHAR*) szConnStringOut,
    			sizeof (szConnStringOut),
    			&cbConnOut,
    			SQL_DRIVER_COMPLETE);
    							
    	if (nstatus != SQL_SUCCESS && nstatus != SQL_SUCCESS_WITH_INFO)
    	{
    		HandleError(hdbc,SQL_HANDLE_DBC,nstatus);
    		return;
    	}
    
    	nstatus = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);	
    
    	nstatus = SQLExecDirect(hstmt, (SQLCHAR*) szDropTable, SQL_NTS);
    	nstatus = SQLExecDirect(hstmt, (SQLCHAR*) szCreateTable, SQL_NTS);
    
    	if (!SQL_SUCCEEDED(nstatus))
    	{
    		HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    	}
    
    	int i;
    	//only one parameter in this case
    	for (i=0; i < nParamCount; i++)
    	{
    		status[i] = SQL_NTS;
    
    
    
    #if LEAK_NUMERIC
    		nstatus = SQLBindParameter(hstmt,
    			i+1,
    			SQL_PARAM_INPUT,
    			SQL_C_CHAR,	
    			SQL_NUMERIC, 
    			10, 
    			0,
    			szParam[i],
    			10,
    			&status[i]);
    #else
    
    		nstatus = SQLBindParameter(hstmt,
    			i+1,
    			SQL_PARAM_INPUT,
    			SQL_C_BINARY,	
    			SQL_WCHAR,
    			10, 
    			0,
    			szParam[i],
    			10,
    			&status[i]);
    #endif
    	
    	
    	}
    
    	nstatus = SQLPrepare(hstmt,(SQLCHAR*) szSelectStatement, SQL_NTS);
    	if (nstatus != SQL_SUCCESS)
    	{
    		HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    	}
    
    	for (i=0; i < 100000; i++)
    	{
    		if (i % 100 == 0)
    		{
    			printf("Selected %d times\n", i);
    			//printf("Inserted %d records\n", i);
    			Sleep(100);
    		}
    		nstatus = SQLExecute(hstmt);
    		if (nstatus != SQL_SUCCESS)
    		{
    			HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    		}
    
    		SQLFreeStmt(hstmt, SQL_CLOSE);
    	}
    
    	nstatus = SQLExecDirect(hstmt, (SQLCHAR*) "DELETE FROM LeakTable", SQL_NTS);
    	if (nstatus != SQL_SUCCESS)
    	{
    		HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    	}
    
    	SQLFreeStmt(hstmt, SQL_CLOSE);
    	SQLDisconnect(hdbc);
    
    }
    
    						
    : 可以使用 LEAK_NUMERIC 常量来演示 SQL_NUMERIC 或 SQL_C_BINARY 泄漏。
  2. 在连接字符串中创建一个新的空 Microsoft Access 数据库所指定的位置。
  3. 开始运行在的代码,然后使用性能监视器来监视进程的专用字节数计数器。

    请注意,专用字节数计数器持续增加运行代码时。

属性

文章编号: 273772 - 最后修改: 2005年9月26日 - 修订: 2.2
这篇文章中的信息适用于:
  • Microsoft Open Database Connectivity Driver for Access 4.0
  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.5 Service Pack 1
关键字:?
kbmt kbhotfixserver kbqfe kbbug kbfix kbjet kbmdac250sp2fix kbwin2000presp2fix KB273772 KbMtzh
机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 273772
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com