# [KB]关于 TiDB 客户端 Prepare Statement 未 Close 导致 TiDB OOM

## Description

集群中 TiDB Server 不断 OOM 重启

## Root Cause

客户端 Prepare Statement 未 Close，导致内存占用持续累积，最终 OOM

## Diagnostic Steps

1. 采集 Profile Debug 方法，IP 地址为 OOM TiDB 服务器的 IP，端口为 OOM TiDB_Status_Port 的端口

    curl -G <http://{TiDBIP}:10080/debug/zip?seconds=30> > profile.zip

    //本例采用的是采集 heap 文本的形式
    curl <http://{TiDBIP}:10080/debug/pprof/heap?debug=1> > heap

2. 查看 profile 文本信息，有类似如下信息（或者查看火焰图快速判断）

    ```golang
        heap profile: 9114(inused objects): 6173217024(inused bytes) [30107(alloc objects): 12649791480(alloc bytes)] @ heap/1048576
        8137: 6132563968 [8137: 6132563968](前面4个数和第一行一样，此行以后是每次记录的信息，后面的地址是记录中的栈指针) @ 0x323a3f1 0x3239797 0x322a2c0 0x3226cd3 0x325a8eb 0x13b42e1
        #    0x323a3f0  github.com/pingcap/tidb/server.(*TiDBStatement).AppendParam+0x190        /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/server/driver_tidb.go:96
        #    0x3239796  github.com/pingcap/tidb/server.(*clientConn).handleStmtSendLongData+0xd6    /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/server/conn_stmt.go:623
        #    0x322a2bf  github.com/pingcap/tidb/server.(*clientConn).dispatch+0xd3f            /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/server/conn.go:1062
        #    0x3226cd2  github.com/pingcap/tidb/server.(*clientConn).Run+0x292                /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/server/conn.go:795
        #    0x325a8ea    github.com/pingcap/tidb/server.(*Server).onConn+0xb1a                /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/server/server.go:477

        1: 7987200 [1: 7987200] @ 0x24c0bf1 0x24be318 0x24bd784 0x24bc2cb 0x13b42e1
        #    0x24c0bf0    github.com/pingcap/tidb/store/copr.(*copIteratorWorker).handleCopResponse+0x820    /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/store/copr/coprocessor.go:949
        #    0x24be317    github.com/pingcap/tidb/store/copr.(*copIteratorWorker).handleTaskOnce+0x857    /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/store/copr/coprocessor.go:735
        #    0x24bd783    github.com/pingcap/tidb/store/copr.(*copIteratorWorker).handleTask+0x1b3    /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/store/copr/coprocessor.go:630
        #    0x24bc2ca    github.com/pingcap/tidb/store/copr.(*copIteratorWorker).run+0xea        /home/jenkins/agent/workspace/optimization-build-tidb-linux-amd/go/src/github.com/pingcap/tidb/store/copr/coprocessor.go:36
    ```

    占用最多的 6132563968/1024/1024/1024 = 5.7 G 

3. 占用最多的栈信息包含的函数 `server.(\*TiDBStatement).AppendParam 和 server.(\*clientConn).handleStmtSendLongData` 代表的是 Prepare statement 执行中。 

4. 查看 Prepare statement 的占用，可以在监控 TiDB--Server--Prepare Statement Count 中查看。

 如果是 TiDB Cloud 需要在 prepared statement gauge 监控添加查询（debug 权限才可以访问），可以看到有大量 prepare statement 

```sql
    tidb_server_prepared_stmts{kubernetes_namespace=~".*$cluster_id",component="tidb"}
```

![image.png](/images/TiDB/know-issue-tidb-prepare-no-close.png)

## Resolution

业务侧需要在 Prepare Statement 使用完成后，在客户端进行关闭。

如果是 Java 可以参考[官方文档](https://docs.pingcap.com/zh/tidb/stable/java-app-best-practices/#使用-prepare-api)来进行配置。

如果是 go 需要在程序侧添加

```
Stmt.Close()
```

## Workaround

NA

## Affect Version(optional)

ALL