go-pg / pg

Golang ORM with focus on PostgreSQL features and performance
https://pg.uptrace.dev/
BSD 2-Clause "Simplified" License
5.67k stars 404 forks source link

Potential Memory Leak in appendRune Function #1987

Closed mateusveloso closed 11 months ago

mateusveloso commented 11 months ago

Expected Behavior

The appendRune function should handle memory allocation efficiently, especially when dealing with large strings.

Current Behavior

The current implementation of appendRune function in go-pg library seems to be causing a memory leak. It creates a new byte slice every time the capacity of the current slice is insufficient to store the new rune. This can lead to a large number of memory allocations, especially when the function is called with large strings.

Possible Solution

A possible solution would be to modify the appendRune function to reuse the already allocated memory as much as possible, instead of always allocating new memory. This can be achieved by doubling the capacity of the existing slice when the current capacity is insufficient.

Steps to Reproduce

  1. Call the appendRune function with a large string.
  2. Monitor the memory usage.
  3. Notice the increase in memory allocation.

Context (Environment)

This issue has been identified while profiling a Go application that uses the go-pg library. The memory leak can potentially affect the performance and stability of applications that use this library.

Detailed Description

The proposed change involves modifying the appendRune function in the go-pg library to handle memory allocation more efficiently. This should help mitigate the memory leak issue and improve the performance of applications using this library.

Possible Implementation

Here is a possible implementation of the proposed change:

func appendRune(b []byte, r rune) []byte {
    if r < utf8.RuneSelf {
        return append(b, byte(r))
    }
    l := len(b)
    if cap(b)-l < utf8.UTFMax {
        nb := make([]byte, l, 2*l+utf8.UTFMax)
        copy(nb, b)
        b = nb
    }
    n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r)
    return b[:l+n]
}

In this version of the function, instead of always creating a new byte slice when the capacity is insufficient, we double the capacity of the existing slice. This should reduce the amount of memory allocated and, therefore, the memory leak.