Repository: opencv
Issue: Open CV cv::resize memory leak. (4.10.0)
Labels: bug,category: imgproc,incomplete,needs investigation

### System Information

OpenCV version: 4.10.0
Operating System / Platform: Ubuntu 20.04
Compiler & compiler version: g++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0
Java Version: openjdk 21.0.4 2024-07-16 LTS

### Detailed description

```c++
#include <opencv2/opencv.hpp>
#include <sys/resource.h>
#include <cstdio>

void print_memory_usage() {
    struct rusage usage;
    getrusage(RUSAGE_SELF, &usage);
    printf("Memory usage: %ld KB\n", usage.ru_maxrss);
}

extern "C" {
    void image_resize(const char* input_path, const char* output_path, int new_width, int new_height) {
        // Read the image from file
        printf("OpenCV version: %d.%d.%d\n", CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION);
        cv::Mat input_image = cv::imread(input_path);
        if (input_image.empty()) {
            printf("Could not read the image: %s\n", input_path);
            return;
        }

        // Create an empty matrix to store the resized image
        cv::Mat resized_image;
        // Resize the image
        cv::resize(input_image, resized_image, cv::Size(new_width, new_height));

        // Write the resized image to file
        cv::imwrite(output_path, resized_image);

        resized_image.release();
        input_image.release();
        print_memory_usage();
    }
}
```

I have a java application where I am loading this library and performing infinite resize operation on a png image, but I notice that after some ~1 Million resize operation my container memory is going to ~99% and eventually pod is being crashed. However JVM heap memory is never going beyond 512M.

![image](https://github.com/user-attachments/assets/99cbdbc3-efd1-4d8e-86ba-4c34e1547497)

Initially I found this bug as part of JavaCv library https://github.com/bytedeco/javacv/issues/2283

I am seeing memory leak in both javacv library as well the native library execution above. And the root cause seems to be opencv library itself.


### Steps to reproduce

```cpp
#include <opencv2/opencv.hpp>
#include <sys/resource.h>
#include <cstdio>

void print_memory_usage() {
    struct rusage usage;
    getrusage(RUSAGE_SELF, &usage);
    printf("Memory usage: %ld KB\n", usage.ru_maxrss);
}

extern "C" {
    void image_resize(const char* input_path, const char* output_path, int new_width, int new_height) {
        // Read the image from file
        printf("OpenCV version: %d.%d.%d\n", CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION);
        cv::Mat input_image = cv::imread(input_path);
        if (input_image.empty()) {
            printf("Could not read the image: %s\n", input_path);
            return;
        }

        // Create an empty matrix to store the resized image
        cv::Mat resized_image;
        // Resize the image
        cv::resize(input_image, resized_image, cv::Size(new_width, new_height));

        // Write the resized image to file
        cv::imwrite(output_path, resized_image);

        resized_image.release();
        input_image.release();
        print_memory_usage();
    }
}
```

![image](https://github.com/user-attachments/assets/4005a034-0a18-4ba1-887a-0a75a9a7ee3f)


```sh
g++ -shared -o libs/libimage_resize.so -fPIC image_resize.cpp -I/usr/local/include/opencv4 -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_imgcodecs
```

```java
package org.example;


// Java 22 Panama Code to Call the C++ Image Resize Function
import java.io.IOException;
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class panama {
    public void resizeImage() throws Throwable {
        // Lookup the resize_image function from the shared library
        long start = System.currentTimeMillis();
        Linker linker = Linker.nativeLinker();
        SymbolLookup lookup = SymbolLookup.loaderLookup();
        Path outputMediaPath = Files.createTempFile("test", ".png");
        MethodHandle resizeHandle = linker.downcallHandle(
                lookup.find("image_resize").orElseThrow(),
                FunctionDescriptor.ofVoid(
                        ValueLayout.ADDRESS, // input_path (const char*)
                        ValueLayout.ADDRESS, // output_path (const char*)
                        ValueLayout.JAVA_INT, // new_width (int)
                        ValueLayout.JAVA_INT  // new_height (int)
                )
        );

        try (Arena arena = Arena.ofConfined()) {
            MemorySegment inputPathSegment = arena.allocateUtf8String("media.png");
            MemorySegment outputPathSegment = arena.allocateUtf8String(String.valueOf(outputMediaPath));

            Integer[] h = {300, 450};
            Integer[] w = {400, 500};
            Random random = new Random();
            Integer newWidth = h[random.nextInt(2)];
            Integer newHeight = w[random.nextInt(2)];
            // Call the native function using Panama's MethodHandle
            resizeHandle.invoke(
                    inputPathSegment,
                    outputPathSegment,
                    newWidth,
                    newHeight
            );
            Files.deleteIfExists(outputMediaPath);
            long end = System.currentTimeMillis();
            System.out.println("time: "+(end-start));
        }
    }

    public static void main(String[] args) {
        System.out.println(System.getProperty("java.library.path"));
        System.load("/home/azureuser/opencv/opencv-so/libs/libimage_resize.so");
        System.out.println("loaded");
        int i = 0;
        int j=0;
        AtomicLong count = new AtomicLong();

        ExecutorService executor = new ThreadPoolExecutor(
                15,                       // Core pool size (number of threads)
                20,                       // Maximum pool size (limit number of threads)
                60L, TimeUnit.SECONDS,     // Time to keep idle threads alive
                new ArrayBlockingQueue<>(1000), // Bounded task queue of size 500
                new ThreadPoolExecutor.CallerRunsPolicy() // Handler when the queue is full
        );// Only allow 1000 tasks to be
        panama app = new panama();
        for(i=0; i < 10000 ; i++) {
            for(j=0; j<10000; j++) {
                executor.submit(() -> {
                    try {
                        app.resizeImage();
                    } catch (Throwable e) {
                        throw new RuntimeException(e);
                    }
                    // Calculate used memory
                    Runtime runtime = Runtime.getRuntime();
                    long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) /(1024*1024);

                    // Total memory currently available to the JVM (committed memory)
                    long committedMemory = runtime.totalMemory() / (1024 * 1024);

                    // Maximum memory the JVM can use (based on the -Xmx setting)
                    long maxMemory = runtime.maxMemory() / (1024* 1024);
                    System.out.println("Used: "+usedMemory+", Commited: "+ committedMemory+", Max: "+ maxMemory);
                });
            }
        }
        executor.shutdown();
    }
}
```

```Dockerfile
FROM eclipse-temurin:21

# Switch to root user for installing libraries
USER root

RUN mkdir -p /path/to/image/folder

RUN mkdir -p /home/azureuser/opencv/opencv-so/libs/
COPY libimage_resize.so /home/azureuser/opencv/opencv-so/libs/
COPY media.png  /home/azureuser/opencv/opencv-so/libs/media.png

# Create necessary directories and install dependencies in a single step
# libgtk required for openCV library.
RUN mkdir -p /opt/app /appl/media \
    && apt-get update -y \
        && apt install libjemalloc-dev -y \
	&&  apt-get install libopencv-dev -y \
         && apt-get install -y libgtk2.0-0 \
         && apt install valgrind -y

RUN apt install build-essential cmake wget unzip git -y

WORKDIR /opencv-build
RUN git clone https://github.com/opencv/opencv.git
WORKDIR /opencv-build/opencv/build
RUN cmake ../
RUN make
RUN make install
COPY startup.sh /opt/app/startup.sh
RUN chmod +x /opt/app/startup.sh
COPY app.jar /opt/app/app-jcv-load.jar

EXPOSE 8080
# Set the working directory
WORKDIR /opt/app

# Command to run the startup script
CMD ["./startup.sh"]
```

* Startup.sh
```sh
#!/bin/sh


#export MALLOC_CONF="prof:true,prof_leak:true,lg_prof_interval:30,lg_prof_sample:17,prof_prefix:/opt/app/prof/"

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

java -Xms512M -Xmx1024M \
#-Dorg.bytedeco.javacpp.maxBytes=1000M \
#-Dorg.bytedeco.javacpp.maxPhysicalBytes=2000M \
#-Dorg.bytedeco.javacpp.nopointergc=true \
--enable-preview -jar app-jcv-load.jar
```


![image](https://github.com/user-attachments/assets/1f01fc2e-f6af-4086-903b-6cc13febf09a)


### Issue submission checklist

- [X] I report the issue, it's not a question
- [X] I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found any solution
- [X] I updated to the latest OpenCV version and the issue is still there
- [X] There is reproducer code and related data files (videos, images, onnx, etc)