Bug #115852 allocated memory to prepared statement are not releaed after connection gone.
Submitted: 16 Aug 14:19 Modified: 16 Aug 15:18
Reporter: ebrahim poursadeghi Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:8.0.37,9.0.1 OS:Any
Assigned to: CPU Architecture:Any

[16 Aug 14:19] ebrahim poursadeghi
Description:
I have a simple script that just simply call prepare statement and close them. when the script is done I expect db to release memory allocated because of this prepared statement but allocated memory won't release.
After running script i get following result as part of running show global status like '%com_stmt%':

Com_stmt_prepare: 300
Com_stmt_close: 300
and memory usage reports following output:
query:

SELECT SUBSTRING_INDEX(event_name,'/',2) AS
                                            code_area, FORMAT_BYTES(SUM(current_alloc))
                                         AS current_alloc
FROM sys.x$memory_global_by_current_bytes
GROUP BY SUBSTRING_INDEX(event_name,'/',2)
ORDER BY SUM(current_alloc) DESC;
output:

memory/performance_schema,220.66 MiB
memory/innodb,192.54 MiB
memory/sql,9.67 MiB
memory/mysys,8.60 MiB
memory/temptable,1.00 MiB
memory/mysqld_openssl,121.38 KiB
memory/mysqlx,3.38 KiB
memory/vio,1.16 KiB
memory/myisam, 728 bytes
memory/csv, 120 bytes
memory/blackhole, 120 bytes
while allocated memory on mysql process is more than 6G
As far as I know in proxysql we have by default 20 prepare statement per connection and if we exceed that the connection will be reset and we expect mysql to release that memory but seems like this is not happening and memory stays allocated.

Example code
package main

import (
	"database/sql"
	"fmt"
	"log"
	"strings"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	dsn := "root:root@tcp(localhost:3306)/tes_db"
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatalf("Failed to connect to the database: %v", err)
	}
	defer db.Close()

	question := "? ,"
	qlen := 0
	for i := 0; i < 300; i++ {
		if i < 40 {
			for i := 0; i < 1000; i++ {
				question += "? ,"
			}
		}
		query := "SELECT " + strings.TrimRight(question, ",")
		qlen += len(query)
		_, err := db.Prepare(query)
		if err != nil {
			log.Fatalf("Failed to prepare statement %d: %v", i, err)
		}

		fmt.Printf("Prepared statement %d\n", i)
	}

	fmt.Println("Finished preparing statements", qlen/1024/1024)
}
Configuration

Go version: run go version 1.22

Server OS: E.g. macos (mysql was on docker)

How to repeat:
By running the script you can see that memory is allocated and it's not released.
[16 Aug 15:18] MySQL Verification Team
Hi Mr. pursadeghi,

Thank you for your bug report.

However, we can not repeat it.

Can you please just send us a set of SQL statements that will produce the same error. 

Next, which memory is not released. If it is about memory taken by mysqld, that is expected behaviour.

Namely, that is how malloc library that comes with the operating systems function

Regarding individual memory, those are sometimes intentionally not released, in order to cache memory for further usage.

Mostly likely, this is not a bug, but we need a repeatable test case as a set of SQL statements. 

Can't repeat.