You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++函数重复调用时内存占用异常问题求助

C++文件读取时内存占用异常问题分析请求

问题背景

在C++开发中处理压缩序列文件时,重复调用读取函数后内存出现异常增长,两次读取相同长度数据但内存占用差异明显,恳请帮忙分析原因。

相关代码

main.cpp

#include <iostream>
#include "seq.h"

int main(int argc, char *argv[]) {
    SnpSite snp_site("/mnt/c/Users/manht/Downloads/s_typhi_wong_holt.aln.gz");
    snp_site.test(); // 第一次调用
    snp_site.test(); // 第二次调用
}

seq.h

#include "file_handler.h"
#include <stdio.h>

class SnpSite {
private:
    string inputfile;
    FileHandler fh;
public:
    SnpSite(char* _inputfile);

    int is_unknown(char base);
    void test();
};

seq.cpp

#include "seq.h"

SnpSite::SnpSite(char* _inputfile) {
    fh = FileHandler();
    inputfile = _inputfile;
}

void SnpSite::test() {
    string sample_name, seq;
    this->fh.open(this->inputfile.c_str());
    this->fh.assign_next_sample_to(&sample_name, &seq);
    this->fh.close();
}

file_handler.h

#ifndef SEQ_H_
#include <zlib.h>
#include <utility>
#include <ctype.h>
#include "my_string.h"
#include <string>

using namespace std;

#define SEQ_H_

typedef bool (*match_func)(int c, int delimiter);

class FileHandler {
private:
    gzFile file;
    char buffer[2048]; // Static allocation for better performance.
    int buffer_start, buffer_end;
    bool eof;
    void get_until(int delimiter, string *s);
public:
    FileHandler();
    FileHandler(int _buffer_size);

    void open(const char* filename);
    void close();
    void assign_next_sample_to(string *name, string *seq);
    int next_char();
    bool is_eof();
};

#endif

file_handler.cpp

#include "file_handler.h"

FileHandler::FileHandler() {
    buffer_start = -1;
    buffer_end = -1;
    eof = false;
}

void FileHandler::open(const char* filename) {
    file = gzopen(filename, "r");
    eof = false;
}

void FileHandler::close() {
    gzclose(file);
}

int FileHandler::next_char() {
    /* Read current character and increase cursor (buffer_start) by 1.*/
    if (buffer_start >= buffer_end) {
        buffer_end = gzread(file, buffer, 2048);
        buffer_start = -1;
        if (buffer_end == 0) eof = true;
    }
    return buffer[++buffer_start];
}

bool FileHandler::is_eof() {
    return eof;
}

#define SEP_SPACE 0 // isspace(): \t, \n, \v, \f, \r
#define SEP_TAB   1 // isspace() && !' '
#define SEP_LINE  2 // line separator: "\n" (Unix) or "\r\n" (Windows)
#define SEP_MAX   2

// list of function to compare c and delimiter, need exactly 2 arguments.
bool match_space(int c, int delimter) {
    return isspace(c);
}
bool match_tab(int c, int delimter) {
    return isspace(c) && c != ' ';
}
bool match_newline(int c, int delimter) {
    return c == '\n';
}
bool match_char(int c, int delimter) {
    return c == delimter;
}
bool no_match(int c, int delimiter) {
    return false;
}
// end list.

void FileHandler::get_until(int delimiter, string *s) {
    /*
        Read till delimiter and append bytes read to s.
        When done cursor will be at the end of the line.
    */
    match_func match; // function to check if a char match delimiter
    switch (delimiter) {
        case SEP_SPACE:
            match = match_space;
            break;
        case SEP_TAB:
            match = match_tab;
            break;
        case SEP_LINE:
            match = match_newline;
            break;
        default:
            if (delimiter > SEP_MAX) match = match_char;
            else match = no_match;
    }

    // begin process
    int i = buffer_start;
    while (!match(buffer[i], delimiter)) {
        if (buffer_start >= buffer_end) {
            buffer_end = gzread(file, buffer, 2048);
            buffer_start = 0;
            i = 0;
            if (buffer_end == 0) {
                eof = true;
                break;
            }
        }
        while (!match(buffer[i], delimiter) && i < buffer_end) i++;
        s->append((char*)(buffer + buffer_start), i - buffer_start);
        buffer_start = i;
    }
}

/* 
    Get next sample name and sequence, assign it to *name and *seq.
    (Note: this function do not read quality score for QUAL file).
*/
void FileHandler::assign_next_sample_to(string *name, string *seq) {
    /* Get next sample name and sequence, assign it to *name and *seq.*/
    name->erase();
    seq->erase();
    int c;
    while (!eof && (c = next_char()) != '>' && c != '@') {} // read until meet sample name
    get_until(SEP_SPACE, name); // get sample name
    while (!eof && (c = next_char()) != '>' && c != '@' && c != '+') {
        if (c == '\n') continue;
        get_until(SEP_LINE, seq); // read sequence
    }
    buffer_start--; // step back to the end of sequence
}

内存使用异常现象

通过htop追踪进程PID的内存使用情况,发现以下异常:

  • 第一次调用test():
    • 函数开始时,进程占用6168 KBytes内存。
    • 函数结束时,进程占用13998 KBytes内存。
  • 第二次调用test():
    • 函数开始时,进程占用6304 KBytes内存。
    • 函数结束时,进程占用21664 KBytes内存。

两次调用中,seq变量长度均为4809037,sample_name长度均为11,无法理解为何内存占用存在显著差异。


内容的提问来源于stack exchange,提问作者manhtr76

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:40:26