MyMonsterCat / RapidOcr-Java

🔥🔥🔥Java代码实现调用RapidOCR(基于PaddleOCR),适配Mac、Win、Linux,支持最新PP-OCRv4
Apache License 2.0
261 stars 38 forks source link

内存占用不释放 #26

Open chuchumaolu555 opened 8 months ago

chuchumaolu555 commented 8 months ago

在spring boot项目中对文字图片进行OCR,每次调用都会增加内存占用,服务重启、停止后内存释放;个人猜测是引擎内缓存了OCR识别内容,可不可以加一个引擎实例销毁的方法,用完可以手动销毁OCR引擎实例?

MyMonsterCat commented 8 months ago

群友在linux下测试内存达到2.3G后就不再增长。 这个问题比较复杂,具体还没有研究,最近比较忙,后面有时间了看一下,还望理解。 如果您解决了这个问题,欢迎提交PR。

loulaner commented 7 months ago

遇到相同的问题,有办法解决吗?

MyMonsterCat commented 7 months ago

遇到相同的问题,有办法解决吗?

暂时没解决,需要从c++方面下手

chuchumaolu555 commented 6 months ago

没有,因为是底层调用逻辑问题,需要作者改底层封装。

在 2024-02-20 12:21:15,"ryan" @.***> 写道:

遇到相同的问题,有办法解决吗?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

harbourge commented 2 months ago

同样的问题+1,有预计的修复时间吗

hp88yx commented 1 month ago

遇到相同的问题,有办法解决吗?

暂时没解决,需要从c++方面下手

OcrResult OcrLite::detect(const char *path, const char *imgName, cv::Mat &src, cv::Rect &originRect, ScaleParam &scale, float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle)

老哥,感觉是这个方法没有把 textBoxPaddingImg资源进行释放,这个由src.clone得到

执行完 drawTextBoxes(textBoxPaddingImg, textBoxes, thickness) 这个方法后,返回结果时用的是textBoxImg进行回写, 所以感觉是textBoxPaddingImg没有进行释放导致的, 在返回结果前加上textBoxPaddingImg.release() 应该就能解决问题

BenzHuang commented 1 month ago

项目:spring boot、jdk17、gradle,其中依赖中引入

implementation("io.github.mymonstercat:rapidocr:0.0.7") 
implementation("io.github.mymonstercat:rapidocr-onnx-linux-x86_64:1.2.2")

controllter:

package cn.test.ocr.controller;

import com.benjaminwan.ocrlibrary.OcrResult;
import io.github.mymonstercat.ocr.InferenceEngine;
import io.github.mymonstercat.ocr.config.ParamConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Monster
 */
@Controller
public class OcrController {
    // VIN码正则表达式:17位,包含大写字母(除了I、O、Q)和数字
    private static final String VIN_REGEX = "\\b[A-HJ-NPR-Z0-9]{17}\\b";
    private static final Pattern VIN_PATTERN = Pattern.compile(VIN_REGEX);

    private static final ParamConfig PARAM_CONFIG = new ParamConfig(50, 0, 0.5F, 0.3F, 1.6F, true, true);
    private static final InferenceEngine INFERENCE_ENGINE = InferenceEngine.getInstance(io.github.mymonstercat.Model.ONNX_PPOCR_V3);

    @Value("${images.path}")
    private String imagesPath;

    //@GetMapping("/")
    @RequestMapping(value = {"/", "/ocr"}, method = RequestMethod.GET)
    public String home() {
        return "index";
    }

    @PostMapping("/ocr")
    public String ocr(@RequestParam("file") MultipartFile fileUpload, Model model) throws IOException {
        if (fileUpload.isEmpty()) {
            model.addAttribute("message", "请选择一个文件上传");
            return "index";
        }

        /*File file = new File(imagesPath + "/" + fileUpload.getOriginalFilename());
        fileUpload.transferTo(file);*/
        //file.deleteOnExit();

        // 存储上传的文件到服务器
        Path filePath = Paths.get(imagesPath, fileUpload.getOriginalFilename());

        // 检查文件是否存在,如果存在则删除(注意:这可能会丢失数据)
        if (Files.exists(filePath)) {
            Files.delete(filePath);
        }
        Files.copy(fileUpload.getInputStream(), filePath);

        String fileUri = "/files/" + filePath.getFileName();
        model.addAttribute("imageUri", fileUri);

        OcrResult ocrResult = INFERENCE_ENGINE.runOcr(filePath.toString(), PARAM_CONFIG);
        //String ocrStr = ocrResult.getStrRes().replaceAll("★", "");
        Matcher matcher = VIN_PATTERN.matcher(ocrResult.getStrRes());
        if (matcher.find()) {
            model.addAttribute("vinCode", "VIN: " + matcher.group());
        } else {
            model.addAttribute("vinCode", "未识别到VIN码,文字读取结果:" + ocrResult.getStrRes());
        }

        //System.gc();
        return "index";
    }
}

服务器配置

4c8g, x86_64

jvm配置参数

-Xms2g -Xmx6g -Xmn2G -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512m -XX:MaxGCPauseMillis=200 -XX:SurvivorRatio=8

在服务器上运行,在上传2-6张图片后java进行被系统强制关闭。通过用top命令看到每次识别内存一直不释放,直接最后出现Out of memory,被系统killed.

在本地mac上开发(gradle引入io.github.mymonstercat:rapidocr-onnx-platform:0.0.7,即使用rapidocr-onnx-macosx-arm64),没有出现出现占用内存不释放问题。有尝试主动调用System.gc()没有解决,求解决Linux上占用内存不释放的办法

chuchumaolu555 commented 1 month ago

有可能,我c++不太懂,再往底层就没排查了 高手们可以追一下看看是否能解决调

在 2024-08-14 11:37:13,"hp88yx" @.***> 写道:

遇到相同的问题,有办法解决吗?

暂时没解决,需要从c++方面下手

OcrResult OcrLite::detect(const char path, const char imgName, cv::Mat &src, cv::Rect &originRect, ScaleParam &scale, float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle)

老哥,感觉是这个方法没有把 textBoxPaddingImg资源进行释放,这个由src.clone得到

执行完 drawTextBoxes(textBoxPaddingImg, textBoxes, thickness) 这个方法后,返回结果时用的是textBoxImg进行回写, 所以感觉是textBoxPaddingImg没有进行释放导致的

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

scvzerng commented 1 week ago

有可能,我c++不太懂,再往底层就没排查了 高手们可以追一下看看是否能解决调 在 2024-08-14 11:37:13,"hp88yx" @.> 写道: 遇到相同的问题,有办法解决吗? 暂时没解决,需要从c++方面下手 OcrResult OcrLite::detect(const char path, const char imgName, cv::Mat &src, cv::Rect &originRect, ScaleParam &scale, float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle) 老哥,感觉是这个方法没有把 textBoxPaddingImg资源进行释放,这个由src.clone得到 执行完 drawTextBoxes(textBoxPaddingImg, textBoxes, thickness) 这个方法后,返回结果时用的是textBoxImg进行回写, 所以感觉是textBoxPaddingImg没有进行释放导致的 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.>

我也不是很懂c++但是我拿benchmark.cpp跑了个死循环(windows系统)然后发现内存基本是在一定范围内波动没有明显的内存泄漏迹象,然后根据gpt的回答

AI Assistant:

当 cv::Mat 对象超出其作用域时,其析构函数会自动调用,管理和释放内存。

OcrResult OcrLite::detect(const char *path, const char *imgName,
                          cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
                          float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle) {

    // textBoxPaddingImg 在 detect 函数返回时会自动被释放

    cv::Mat textBoxPaddingImg = src.clone();

    // ... 你的代码 ...

    // textBoxPaddingImg 超出作用域并会自动调用析构函数
}

结合跑benchmark的时候内存无明显泄漏情况下可能和这个无关,当然c++方面我也不是很懂