【问题标题】:Enormous Increase In the Use Of Memory内存使用量大幅增加
【发布时间】:2011-06-18 09:07:18
【问题描述】:

我有一个代码,我需要创建一个键值为 double 的映射(两个集群之间的 f 检验的值。我需要为此计算残差平方和)和 cluspair 的映射值这是我创建的类 Cluster 的对。 Map 旨在存储所有集群之间的 F 检验值,这样我就不需要在每一步中一次又一次地进行计算。 BTW簇是一个树形结构,每个簇包含两个子簇,存储的值是70维向量。

问题是,为了计算 RSS,我需要实现一个递归代码,在该代码中我需要找到集群中每个元素的距离以及集群的平均值,这似乎消耗了大量的内存.当我创建相同的映射时,键值是两个集群的平均值之间的简单距离,程序使用的内存最少,所以我认为内存使用量的增加是由递归函数 RSS 的调用引起的。我应该怎么做才能管理下面代码中的内存使用?在其当前实现中,系统内存不足,Windows 关闭应用程序,说系统虚拟内存不足。

主要代码:

    map<double,cluspair> createRSSMap( list<Cluster*> cluslist )
    {
            list<Cluster*>::iterator it1;
            list<Cluster*>::iterator it2;

            map<double,cluspair> rtrnmap;


            for(it1=cluslist.begin(); it1!= --cluslist.end() ;it1++)
            {
                it2=it1;
                ++it2;
                cout << ".";

                list<Cluster*>::iterator itc;
                double cFvalue=10000000000000000000;
                double rIt1 = (*it1)->rss();

                for(int kk=0 ; it2!=cluslist.end(); it2++)
                {

                    Cluster tclustr ((*it1) , (*it2));
                    double r1 = tclustr.rss();
                    double r2= rIt1 + (*it2)->rss();
                    int df2 = tclustr.getNumOfVecs() - 2;

                    double fvalue = (r1 - r2) / (r2 / df2);

                    if(fvalue<cFvalue)
                    {
                        cFvalue=fvalue;
                        itc=it2;
                    }
                }


                cluspair clp;
                clp.c1 = *it1;
                clp.c2 = *itc;


                bool doesexists = (rtrnmap.find(cFvalue) != rtrnmap.end());

                while(rtrnmap)
                {
                    cFvalue+= 0.000000001;
                    rtrnmap= (rtrnmap.find(cFvalue) != rtrnmap.end());
                }

                rtrnmap[cFvalue] = clp;


            }

            return rtrnmap;
    }

以及RSS函数的实现:

double Cluster::rss()
{
    return rss(cnode->mean);
}

double Cluster::rss(vector<double> &cmean)
{
    if(cnode->numOfVecs==1)
    {
        return vectorDist(cmean,cnode->mean);
    }
    else
    {
        return ( ec1->rss(cmean) + ec2->rss(cmean) );       
    }
}

提前非常感谢。我现在真的不知道该怎么办。


下面是我用来创建地图的代码,其中的键是两个聚类平均值之间的简单欧几里得距离。正如我上面所说,它非常相似并且使用最少的内存。它仅在 fvalue 的计算上有所不同。不是递归计算,而是计算两个簇的均值的简单距离。希望它有助于识别问题

map<double,cluspair> createDistMap( list<Cluster*> cluslist )
{
        list<Cluster*>::iterator it1;
        list<Cluster*>::iterator it2;

        map<double,cluspair> rtrnmap;


        for(it1=cluslist.begin(); it1!= --cluslist.end() ;it1++)
        {
            it2=it1;
            ++it2;
            cout << ".";

            list<Cluster*>::iterator itc;
            double cDist=1000000000000000;

            for(int kk=0 ; it2!=cluslist.end(); it2++)
            {
                double nDist = vectorDist( (*it1)->getMean(),(*it2)->getMean());
                if (nDist<cDist)
                {
                    cDist = nDist;
                    itc=it2;
                }
            }   

            cluspair clp;
            clp.c1 = *it1;
          clp.c2 = *itc;



            bool doesexists = (rtrnmap.find(cDist) != rtrnmap.end());

            while(doesexists)
            {
                cDist+= 0.000000001;
                doesexists  = (rtrnmap.find(cDist) != rtrnmap.end());
            }

            rtrnmap[cDist] = clp;

        }

        return rtrnmap;
}

vectorDist()的实现

double vectorDist(vector<double> vec1, vector<double> vec2)
{

    double sqrsum=0;
    double tempd=0;

    int vs = vec1.size();

    for ( int i=0;i<vs;i++)
    {
        tempd = vec1[i] - vec2[i];
        sqrsum += tempd*tempd;
    }

    return sqrsum;
}

编辑:

顺便说一句,我已经尝试过这种替代实现,但仍然无法控制内存使用情况

double Cluster::rss()
{
    list<double> fvals;
    rss(cnode->mean , fvals);

    double sum=0;
    list<double>::iterator tpit;
    for(tpit=fvals.begin() ; tpit != fvals.end() ; ++tpit)
    {
        sum += *tpit;
    }
    return sum;
}

void Cluster::rss(vector<double> &cmean , list<double> &fvals)
{
    if(cnode->numOfVecs==1)
    {
        fvals.push_back( vectorDist(cmean,cnode->mean) );
    }
    else
    {
        ec1->rss(cmean , fvals);
        ec2->rss(cmean , fvals);        
    }
}

【问题讨论】:

  • 用编程语言标记它
  • 这个while循环合法吗?另外,考虑不返回地图的副本,而是接受它作为参考参数
  • Cluster::rss() 如何“减少”每次迭代的工作量?请发布先编译的内容...
  • 每次迭代都减少工作量是什么意思?原始代码相当广泛,有很多步骤。我引用的函数是我用来创建 的映射的部分,正如我所提到的。
  • 顺便说一句,我正在添加一个类似的函数来创建一个带有简单距离键的地图,而不是 f 检验计算。它非常相似,但在我所说的部分不同,它使用的内存非常少。希望它有助于识别问题

标签: c++ memory recursion tree


【解决方案1】:

如果您的内存不足,您的树很深,或者您的集群对象很大,或者两者兼而有之。尝试创建另一个与集群树具有相同拓扑结构的双精度树数据结构,并将其称为 RSS 树来保存 RSS 值。计算底部节点的 rss 值,然后递归地填写 RSS 树中的其余值。这样,您在进行 rss 计算时就不会将集群对象保存在内存中。

【讨论】:

  • 我担心集群树既大又深 :) 我明白你的意思,我没想到集群对象一直保存在内存中直到计算结束。我会试一试,但我仍然不确定。我正在返回对对象进行的计算结果。对象本身是否也保存在内存中?
  • 每次对 rss 的递归调用都将调用它的 Cluster 对象的成员变量存储在堆栈上,然后再将新的 Cluster::rss 调用放入调用堆栈。如果您在树中的深度为 100 层,那么您将在调用堆栈中的内存中从上层递归调用中保存多达 300 个集群对象(因为每个集群对象都有一对集群对象作为成员)加上其他任何东西Cluster 对象拥有的成员数据。当你调用一个函数时,通常你将本地数据保存在堆栈中,直到它返回。
  • 但是计算底部节点的rss不会引起同样的深度问题吗?为了到达底部节点,我仍然需要存储以前的集群对象。
  • 不一定。您想在树中进行深度优先搜索,当您点击一个两个子节点都为空的节点时,将该节点的 rss 放入 rss 树中并继续。您可以在搜索树时维护一堆指向仍需探索的集群对象的指针或引用,以便内存使用仅限于您正在查看的一个集群节点以及指向您仍然拥有的集群对象的指针堆栈探索。更多关于深度优先搜索的详细信息可以在维基百科或更好的算法文本中找到。
猜你喜欢
  • 1970-01-01
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
相关资源
最近更新 更多