std :: string内存管理

| 我在使用std :: string进行内存管理时遇到问题。 我有应用程序-具有分离线程的多线程服务器(我确实需要加入它们,它们将完成工作并退出),我发现一段时间后内存使用率很高。我已经开始试验问题出在哪里,并且已经创建了演示该问题的测试程序
#include <iostream>

#include <string>
#include <pthread.h>

pthread_t           thread[100];

using namespace std;

class tst {
    public:
        tst() {
            //cout << \"~ Create\" << endl;
        }
        ~tst() {
            //cout << \"~ Delete\" << endl;
        }
        void calc() {
            string TTT;
            for (int ii=0; ii<100000; ii++) {
                TTT+=\"abcdenbsdmnbfsmdnfbmsndbfmsndb \";
            }
        }
};

void *testThread (void *arg) {
    int cnt=*(int *) arg;
    cout << cnt << \" \";
    tst *TEST=new tst;
    TEST->calc();
    delete TEST;
    pthread_exit((void *)0);
}

int main (int argc, char * const argv[]) {

cout << \"---------------------------------------------------\" << endl;
sleep(5);

    for (int oo=0; oo<100; oo++) {
        pthread_create(&thread[oo], NULL, testThread, &oo);
        pthread_detach(thread[oo]);
    }
    cout << endl;
    cout << \"---------------------------------------------------\" << endl;

    sleep(5);

    for (int oo=0; oo<100; oo++) {
        pthread_create(&thread[oo], NULL, testThread, &oo);
        pthread_detach(thread[oo]);
    }
    cout << endl;
    cout << \"---------------------------------------------------\" << endl;

    sleep(5);
    exit(0);
}
第一个“-”之后的内存使用量为364KB,第二个为19MB,第二个为33.5MB。 还有一件奇怪的事情-每次运行显示不同的内存使用情况,但大多数情况下,最后一个内存使用情况要比第二个“-”之后多50%。 我曾期望,如果删除类TEST(tst),那么字符串也将释放其内存-我发现线程不会这样做-这就是为什么我要创建新的tst,运行它并然后删除。 在我的程序中,这引起了一个大问题,因为我在每个线程中使用的字符串很少,并且一段时间后内存使用量超过了演出;-( 有什么选择如何在字符串后“清空”内存? 我已经尝试了TTT = \“ \”或TTT.clear()而不进行任何更改。 ...我需要使用线程-它将在multicpu机器上运行,其中线程是使用它的“全功能”的唯一选择(据我所知)     
已邀请:
calc
函数退出后,ѭ1中的字符串使用的内存将被释放。删除每个“ 3”对象与它无关,因为没有类成员。 我认为您所看到的是可能正在运行200个线程。由于您分离了所有线程并且从不加入它们,因此您无法保证在开始下一个100之前,前100个线程实际上已经完成。 另外,由于您是通过追加来一次又一次地扩展这些字符串,而同时又在其他线程中分配内存,因此我想您的堆碎片确实非常糟糕。假设一个线程刚刚释放了一个256字节字符串的内存。其他线程已经在前面运行,它们都不再需要256字节的字符串了。现在,该空间已被浪费,但仍分配给程序。 一些可能有帮助的选项: 在将数据放入字符串之前,请使用
.reserve(your_largest_expected_string_size)
。这将有助于避免碎片问题,因为几乎所有字符串的大小都相同。 自定义的字符串分配器类。你可以自己写。 您可以用诸如jemalloc或tcmalloc之类的东西来替换堆分配器。 对于处理来来往往的客户端的服务器应用程序,您可以使用每个客户端的内存池来获得出色的性能。在一个块中分配一个大的内存池。使所有分配使用池(通过STL分配器参数),并且当客户端退出时释放整个池。     
我怀疑您本身遇到的是内存碎片问题,而不是内存泄漏问题。由于您不等待线程退出,因此有多达200个线程试图同时分配内存。此外,默认的内存分配策略为ѭ5,每次需要增长时,它将使当前分配加倍,并且您可能很快就会消耗掉地址空间。 您可以做的一件很简单的事情来缓解问题,方法是使用
reserve()
为字符串预分配内存。在这种情况下,您的字符串为(31 * 100,000)+ 1个字节长,因此您可以按以下方式修改
calc()
string TTT;

// We know how big the string will get, so pre-alloc memory for it to avoid the 
// inefficiencies of the default allocation strategy as the string grows.

TTT.reserve(3100001);

for (int ii=0; ii<100000; ii++) {
    TTT+=\"abcdenbsdmnbfsmdnfbmsndbfmsndb \";
}
这将在单个连续的块中为字符串分配一次内存,并避免了您现在正遭受的很多碎片。在Valgrind下对该更改进行的快速测试表明,原始代码在整个过程的生命周期内总共分配了约1.5 GB;但修改后的版本确实分配了大约620 MB的内存。 同样值得注意的是,Valgrind没有发现任何内存泄漏。如果您认为程序中存在内存问题,那就总是尝试一下是个好主意:Valgrind home。     
calc函数退出后,该字符串应立即取消分配,因为它是局部变量。 您正在使用什么来跟踪内存使用情况?您可能会看到内存碎片,而不是增加内存使用率。这是一个可以证明您的内存是否碎片化的工具:http://hashpling.org/asm/ 我对pthreads并不熟悉,所以我无法确定线程是否存在问题或与未释放的API相关的其他问题。     
根据new和delete(或free()和malloc())的实现,在删除/释放之后,您的内存可能不会交还给操作系统。不需要内存分配器。后续的新内存可能仍会回收内存,或者在内部内存碎片整理或垃圾回收之后,内存使用量可能会再次减少。     
通过将“线程例程”放在另一个范围中来解决问题-if(1){..} 因为正如我在一些论坛上发现的那样,线程在退出时未调用析构函数,所以在这种情况下(如果阻塞则不添加),每个创建的线程都会为\'int cnt \'分配内存,并且永远不会被释放
void *testThread (void *arg) {
    if (1) {
        int cnt=*(int *) arg;
        cout << cnt << \" \";
        tst *TEST=new tst;
        TEST->calc();
        delete TEST;
    }
    pthread_exit((void *)0);
}
...我在项目中发现了几个小错误,但这是主要问题     

要回复问题请先登录注册