【问题标题】:shared_ptr: horrible speedshared_ptr:可怕的速度
【发布时间】:2011-04-07 09:13:41
【问题描述】:

在比较指针的两种变体(经典指针与 shared_ptr)时,我对程序运行速度的显着提高感到惊讶。为了测试 2D Delaunay 增量插入算法已被使用。

编译器设置:

VS 2010(发布)/O2 /MD /GL,W7 Prof,CPU 3.GHZ DualCore

结果:

shared_ptr (C++ 0x00):

N[points]         t[sec]  
100 000                6  
200 000               11  
300 000               16  
900 000               36  

指针:

N[points]         t[sec]  
100 000              0,5  
200 000               1  
300 000               2  
900 000               4   

shared_ptr 版本的运行时间大约长 10 倍。这是编译器设置造成的还是C++ 0x00 shared_ptr 实现太慢了?

VS2010 Profiler:对于原始指针,大约 60% 的时间用于启发式搜索包含插入点的三角形(没关系,这是众所周知的事实)。但是对于 shared_ptr 版本,大约 58% 的时间用于使用 shared_ptr.reset() 并且只有 10% 用于启发式搜索。

使用原始指针测试代码:

void DT2D::DT ( Node2DList *nl, HalfEdgesList *half_edges_dt, bool print )
{
    // Create 2D Delaunay triangulation using incremental insertion method
    unsigned int nodes_count_before = nl->size();

    // Remove duplicit points
    nl->removeDuplicitPoints();

    // Get nodes count after deletion of duplicated points
    unsigned int nodes_count_after = nl->size();

    //Print info
    std::cout << "> Starting DT, please wait... ";
    std::cout << nodes_count_after << " points, " << ( nodes_count_before - nodes_count_after ) << " removed.";

    // Are in triangulation more than three points
    try
    {
            //There are at least 3 points
            if ( nodes_count_after > 2 )
            {
                    // Create simplex triangle
                    createSimplexTriangle ( nl, half_edges_dt );

                    // Increment nodes count
                    nodes_count_after += 3;

                    // Starting half edge using for searching
                    HalfEdge *e_heuristic = ( *half_edges_dt ) [0];

                    // Insert all points into triangulation using incremental method
                    for ( unsigned int i = 3; i < nodes_count_after; i++ )  // Jump over simplex
                    {
                            DTInsertPoint ( ( *nl ) [i], &e_heuristic, half_edges_dt );
                    }

                    //Corect boundary triangles (swap edges in triangles adjacent to simplex triangles).
                    //They are legal due to DT, but not creating the convex hull )
                    correctBoundaryTriangles ( nl, half_edges_dt );

                    // Remove triangles having simplex points
                    removeSimplexTriangles ( nl, half_edges_dt );
            }

            //Print results
            std::cout << " Completed." << std::endl;
    }

插入点程序:

void DT2D::DTInsertPoint ( Point2D *p, HalfEdge **e1, HalfEdgesList *half_edges_dt )
{
    // One step of the Delaunay triangulation, incremental insertion by de Berg (2001)
    short   status = -1;

    //Pointers
    HalfEdge *e31 = NULL;
    HalfEdge *e21 = NULL;
    HalfEdge *e12 = NULL;
    HalfEdge *e32 = NULL;
    HalfEdge *e23 = NULL;
    HalfEdge *e13 = NULL;
    HalfEdge *e53 = NULL;
    HalfEdge *e44 = NULL;
    HalfEdge *e63 = NULL;

    try
    {
            // Test, if point lies inside triangle
            *e1 = LawsonOrientedWalk::findTriangleWalk ( p, &status, *e1, 0 );

            if ( e1 != NULL )
            {
                    // Edges inside triangle lies the point
                    HalfEdge *e2 = ( *e1 )->getNextEdge();
                    HalfEdge *e3 = e2->getNextEdge();

                    // Point lies inside the triangle
                    if ( status == 1 )
                    {
                            // Create first new triangle T1, twin edges set after creation
                            e31 = new HalfEdge ( p, *e1, NULL );
                            e21 = new HalfEdge ( e2->getPoint(), e31, NULL );
                            ( *e1 )->setNextEdge ( e21 );

                            // Create second new triangle T2, twin edges set after creation
                            e12 = new HalfEdge ( p, e2, NULL );
                            e32 = new HalfEdge ( e3->getPoint(), e12, NULL );
                            e2->setNextEdge ( e32 );

                            // Create third new triangle T3, twin edges set after creation
                            e23 = new HalfEdge ( p, e3, NULL );
                            e13 = new HalfEdge ( ( *e1 )->getPoint(), e23, NULL );
                            e3->setNextEdge ( e13 );

                            // Set twin edges in T1, T2, T3
                            e12->setTwinEdge ( e21 );
                            e21->setTwinEdge ( e12 );
                            e13->setTwinEdge ( e31 );
                            e31->setTwinEdge ( e13 );
                            e23->setTwinEdge ( e32 );
                            e32->setTwinEdge ( e23 );

                            // Add new edges into list
                            half_edges_dt->push_back ( e21 );
                            half_edges_dt->push_back ( e12 );
                            half_edges_dt->push_back ( e31 );
                            half_edges_dt->push_back ( e13 );
                            half_edges_dt->push_back ( e32 );
                            half_edges_dt->push_back ( e23 );

                            // Legalize triangle T1
                            if ( ( *e1 )->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, *e1 );
                            }

                            // Legalize triangle T2
                            if ( e2->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e2 );
                            }

                            // Legalize triangle T3
                            if ( e3->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e3 );
                            }
                    }

                    // Point lies on the edge of the triangle
                    else if ( status == 2 )
                    {
                            // Find adjacent triangle
                            HalfEdge *e4 = ( *e1 )->getTwinEdge();
                            HalfEdge *e5 = e4->getNextEdge();
                            HalfEdge *e6 = e5->getNextEdge();

                            // Create first new triangle T1, twin edges set after creation
                            e21 = new HalfEdge ( p, e3, NULL );
                            ( *e1 )->setNextEdge ( e21 );

                            // Create second new triangle T2, OK
                            e12 = new HalfEdge ( p, e2, e4 );
                            e32 = new HalfEdge ( e3->getPoint(), e12, e21 );
                            e2->setNextEdge ( e32 );

                            // Create third new triangle T3, twin edges set after creation
                            e53 = new HalfEdge ( p, e6, NULL );
                            e4->setNextEdge ( e53 );

                            // Create fourth new triangle T4, OK
                            e44 = new HalfEdge ( p, e5, *e1 );
                            e63 = new HalfEdge ( e6->getPoint(), e44, e53 );
                            e5->setNextEdge ( e63 );

                            // Set twin edges in T1, T3
                            e21->setTwinEdge ( e32 );
                            ( *e1 )->setTwinEdge ( e44 );
                            e53->setTwinEdge ( e63 );
                            e4->setTwinEdge ( e12 );

                            // Add new edges into list
                            half_edges_dt->push_back ( e21 );
                            half_edges_dt->push_back ( e12 );
                            half_edges_dt->push_back ( e32 );
                            half_edges_dt->push_back ( e53 );
                            half_edges_dt->push_back ( e63 );
                            half_edges_dt->push_back ( e44 );

                            // Legalize triangle T1
                            if ( e3->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e3 );
                            }

                            // Legalize triangle T4
                            if ( e5->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e5 );
                            }

                            // Legalize triangle T3
                            if ( e6->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e6 );
                            }

                            // Legalize triangle T2
                            if ( e2->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e2 );
                            }
                    }
            }
    }
    //Throw exception
    catch ( std::bad_alloc &e )
    {
            //Free memory
            if ( e31 != NULL ) delete e31;
            if ( e21 != NULL ) delete e21;
            if ( e12 != NULL ) delete e12;
            if ( e32 != NULL ) delete e32;
            if ( e23 != NULL ) delete e23;
            if ( e13 != NULL ) delete e13;
            if ( e53 != NULL ) delete e53;
            if ( e44 != NULL ) delete e44;
            if ( e63 != NULL ) delete e63;

            //Throw exception
            throw ErrorBadAlloc ( "EErrorBadAlloc: ", "Delaunay triangulation: Can not create new triangles for inserted point p." );
    }

    //Throw exception
    catch ( ErrorMathZeroDevision &e )
    {
            //Free memory
            if ( e31 != NULL ) delete e31;
            if ( e21 != NULL ) delete e21;
            if ( e12 != NULL ) delete e12;
            if ( e32 != NULL ) delete e32;
            if ( e23 != NULL ) delete e23;
            if ( e13 != NULL ) delete e13;
            if ( e53 != NULL ) delete e53;
            if ( e44 != NULL ) delete e44;
            if ( e63 != NULL ) delete e63;

            //Throw exception
            throw ErrorBadAlloc ( "EErrorMathZeroDevision: ", "Delaunay triangulation: Can not create new triangles for inserted point p." );
    }
}

用 shared_ptr 测试代码:

代码在没有任何优化的情况下被重写...

void DT2D::DTInsertPoint ( std::shared_ptr <Point2D> p, std::shared_ptr <HalfEdge> *e1, HalfEdgesList * half_edges_dt )
{
    // One step of the Delaunay triangulation, incremental insertion by de Berg (2001)
    short   status = -1;

    //Pointers
    std::shared_ptr <HalfEdge> e31;
    std::shared_ptr <HalfEdge> e21;
    std::shared_ptr <HalfEdge> e12;
    std::shared_ptr <HalfEdge> e32;
    std::shared_ptr <HalfEdge> e23;
    std::shared_ptr <HalfEdge> e13;
    std::shared_ptr <HalfEdge> e53;
    std::shared_ptr <HalfEdge> e44;
    std::shared_ptr <HalfEdge> e63;

    try
    {
            // Test, if point lies inside triangle
            *e1 = LawsonOrientedWalk::findTriangleWalk ( p, &status, *e1, 0 );

            if ( e1 != NULL )
            {
                    // Edges inside triangle lies the point
                    std::shared_ptr <HalfEdge> e2((*e1 )->getNextEdge());
                    std::shared_ptr <HalfEdge> e3(e2->getNextEdge());

                    // Point lies inside the triangle
                    if ( status == 1 )
                    {
                            // Create first new triangle T1, twin edges set after creation
            e31.reset( new HalfEdge ( p, *e1, NULL ));
                            e21.reset( new HalfEdge ( e2->getPoint(), e31, NULL ));
                            ( *e1 )->setNextEdge ( e21 );

                            // Create second new triangle T2, twin edges set after creation
                            e12.reset( new HalfEdge ( p, e2, NULL ));
                            e32.reset( new HalfEdge ( e3->getPoint(), e12, NULL ));
                            e2->setNextEdge ( e32 );

                            // Create third new triangle T3, twin edges set after creation
                            e23.reset( new HalfEdge ( p, e3, NULL ));
                            e13.reset( new HalfEdge ( ( *e1 )->getPoint(), e23, NULL ));
                            e3->setNextEdge ( e13 );

                            // Set twin edges in T1, T2, T3
                            e12->setTwinEdge ( e21 );
                            e21->setTwinEdge ( e12 );
                            e13->setTwinEdge ( e31 );
                            e31->setTwinEdge ( e13 );
                            e23->setTwinEdge ( e32 );
                            e32->setTwinEdge ( e23 );

                            // Add new edges into list
                            half_edges_dt->push_back ( e21 );
                            half_edges_dt->push_back ( e12 );
                            half_edges_dt->push_back ( e31 );
                            half_edges_dt->push_back ( e13 );
                            half_edges_dt->push_back ( e32 );
                            half_edges_dt->push_back ( e23 );

                            // Legalize triangle T1
                            if ( ( *e1 )->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, *e1 );
                            }

                            // Legalize triangle T2
                            if ( e2->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e2 );
                            }

                            // Legalize triangle T3
                            if ( e3->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e3 );
                            }
                    }

                    // Point lies on the edge of the triangle
                    else if ( status == 2 )
                    {
                            // Find adjacent triangle
                            std::shared_ptr <HalfEdge> e4 = ( *e1 )->getTwinEdge();
                            std::shared_ptr <HalfEdge> e5 = e4->getNextEdge();
                            std::shared_ptr <HalfEdge> e6 = e5->getNextEdge();

                            // Create first new triangle T1, twin edges set after creation
                            e21.reset(new HalfEdge ( p, e3, NULL ));
                            ( *e1 )->setNextEdge ( e21 );

                            // Create second new triangle T2, OK
                            e12.reset(new HalfEdge ( p, e2, e4 ));
                            e32.reset(new HalfEdge ( e3->getPoint(), e12, e21 ));
                            e2->setNextEdge ( e32 );

                            // Create third new triangle T3, twin edges set after creation
                            e53.reset(new HalfEdge ( p, e6, NULL ));
                            e4->setNextEdge ( e53 );

                            // Create fourth new triangle T4, OK
                            e44.reset(new HalfEdge ( p, e5, *e1 ));
                            e63.reset(new HalfEdge ( e6->getPoint(), e44, e53 ));
                            e5->setNextEdge ( e63 );

                            // Set twin edges in T1, T3
                            e21->setTwinEdge ( e32 );
                            ( *e1 )->setTwinEdge ( e44 );
                            e53->setTwinEdge ( e63 );
                            e4->setTwinEdge ( e12 );

                            // Add new edges into list
                            half_edges_dt->push_back ( e21 );
                            half_edges_dt->push_back ( e12 );
                            half_edges_dt->push_back ( e32 );
                            half_edges_dt->push_back ( e53 );
                            half_edges_dt->push_back ( e63 );
                            half_edges_dt->push_back ( e44 );

                            // Legalize triangle T1
                            if ( e3->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e3 );
                            }

                            // Legalize triangle T4
                            if ( e5->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e5 );
                            }

                            // Legalize triangle T3
                            if ( e6->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e6 );
                            }

                            // Legalize triangle T2
                            if ( e2->getTwinEdge() != NULL )
                            {
                                    legalizeTriangle ( p, e2 );
                            }
                    }
            }
    }
    //Throw exception
    catch ( std::bad_alloc &e )
    {
    /*
            //Free memory
            if ( e31 != NULL ) delete e31;
            if ( e21 != NULL ) delete e21;
            if ( e12 != NULL ) delete e12;
            if ( e32 != NULL ) delete e32;
            if ( e23 != NULL ) delete e23;
            if ( e13 != NULL ) delete e13;
            if ( e53 != NULL ) delete e53;
            if ( e44 != NULL ) delete e44;
            if ( e63 != NULL ) delete e63;
    */
            //Throw exception
            throw ErrorBadAlloc ( "EErrorBadAlloc: ", "Delaunay triangulation: Can not create new triangles for inserted point p." );
    }

    //Throw exception
    catch ( ErrorMathZeroDevision &e )
    {
    /*
            //Free memory
            if ( e31 != NULL ) delete e31;
            if ( e21 != NULL ) delete e21;
            if ( e12 != NULL ) delete e12;
            if ( e32 != NULL ) delete e32;
            if ( e23 != NULL ) delete e23;
            if ( e13 != NULL ) delete e13;
            if ( e53 != NULL ) delete e53;
            if ( e44 != NULL ) delete e44;
            if ( e63 != NULL ) delete e63;
    */
            //Throw exception
            throw ErrorBadAlloc ( "EErrorMathZeroDevision: ", "Delaunay triangulation: Can not create new triangles for inserted point p." );
    }
}

感谢您的帮助...

编辑

我用别名传递 & 替换了所有对象的直接传递。复制构造函数的使用比以前少了。

shared_ptr 的更新表

shared_ptr (C++ 0x00) 旧:

N[points]         t[sec]     
100 000                6   
200 000               11   
300 000               16    
900 000               36   

shared_ptr (C++ 0x00) 新版本:

N[points]         t[sec]      
100 000                2  
200 000                5  
300 000                9  
900 000               24  

有相当大的改进,但 shared_ptr 版本仍然比原始指针版本慢 4 倍。恐怕程序的运行速度不能显着提高。

【问题讨论】:

  • 这也取决于使用的实现。没有代码来测试它,结果不能被认真对待。 (例如,指针是否在两个版本中、只有一个版本中或没有?)
  • 您使用的是std::tr1::shared_ptr 还是Boost shared_ptr? VS2010 也有很多问题(还没有生产质量 IME)。你能在某处分享源代码吗?
  • @luiscubal:关于解除分配的要点。如果原始指针版本没有释放内存,当然它会快得多。它仍然会更慢,因为 shared_ptr 只是需要做更多的工作,但这是一个很大的不同。
  • @dirkgently:我正在使用 std::shared_ptr。 >> 你能在某处分享源代码吗?这是个问题,恐怕我做不到。它适用于完整的拓扑模型,并且有 40 多个类 :-(.
  • 也许unique_ptr 会是更好的选择,因为从外观上看,您并没有共享资源。

标签: c++ performance compiler-construction shared-ptr


【解决方案1】:

在“发布”模式下尝试一下,看看是否能获得更接近的基准。调试模式往往会打开 STL 中的大量断言,这会减慢很多事情的速度。

【讨论】:

  • 此外,MSVC 中 STL 的调试版本具有全局锁,可防止获得使用多核的好处。见stackoverflow.com/questions/2832023/…
  • /MD 暗示这已经是发布模式。 /MDd 将是调试。我同意在 Debug 中进行分析会浪费时间,但这里似乎并非如此。 msdn.microsoft.com/en-us/library/2kzt1wy3(VS.80).aspx
  • 调试版的 MSVC 还有一个可怕的东西叫做_HAS_ITERATOR_DEBUGGING——它会减慢速度很多
  • 啊,我完全忘了看你的cflags。我会同意其他人所说的:确保您的指针实际上已在原始指针代码中被删除,否则您将苹果与橙子进行比较,并且基本上说“我的内存泄漏代码比我的非泄漏代码更快。 "
  • @dirkgently - 迭代器调试帮助我发现了很多错误。我喜欢。如果性能太差,您可以随时关闭它!
【解决方案2】:

没有更多数据是不可能回答这个问题的。您是否分析了代码以准确识别 shared_ptr 版本中减速的根源?使用容器肯定会增加开销,但如果它让它慢 10 倍,我会感到惊讶。

VSTS 有很好的性能工具,如果你可以运行 30 秒左右,它会准确地确定 CPU 使用率。如果您无权访问 VS 性能工具或其他分析工具集,则在调试器中运行 shared_ptr 代码并对其进行 10 或 15 次破解,以获取其花费所有时间的蛮力样本。我发现,这种方法的效果令人惊讶且有悖常理。

[编辑] 不要在该代码变体中按值传递 shared_ptr - 使用 ref 到 const。如果这个函数被大量调用,这将产生可测量的 -ve 影响。

【讨论】:

  • VS2010 Profiler:对于原始指针,大部分时间用于三角形的启发式创建。但是对于 shared_ptr 版本,58% 的时间都花在使用 shared_ptr.reset()
  • 使用 boost::shared_ptr 重试此分析对您来说有多容易?
  • 感谢您的评论...我怎么会忘记使用&...我重写了代码,结果更好。但是代码仍然慢得多,请看一下编辑...
  • 太好了 - 现在,从哪里调用 shared_ptr.reset()?如果那是(是?)你 58% 的时间,那么减少调用次数应该是一个很大的胜利。您是否更新了调整分析? v 虽然没有完整的源代码,但很难提供帮助。
【解决方案3】:

默认情况下,如果您以天真的方式创建共享指针(即shared_ptr&lt;type&gt; p( new type )),则会产生两次内存分配,一个用于实际对象,另一个用于引用计数。您可以通过使用 make_shared 模板来避免额外分配,该模板将为对象和引用计数执行单个实例化,然后就地构造对象。

与对 malloc 的调用加倍相比,其余的额外成本非常小,例如递增和递减计数(都是原子操作)和测试删除。如果您可以提供一些关于如何使用指针/共享指针的代码,您可能会更好地了解代码中实际发生的情况。

【讨论】:

    【解决方案4】:

    shared_ptr 是有史以来最复杂的指针类型:

    • 引用计数需要时间
    • 多重分配(有3部分:对象、计数器、删除器)
    • 用于类型擦除的许多虚拟方法(在计数器和删除器中)
    • 在多个线程之间工作(因此同步)

    有两种方法可以让它们更快:

    • 使用 make_shared 分配它们,因为(不幸的是)普通构造函数分配两个不同的块:一个用于对象,一个用于计数器和删除器。
    • 不要复制它们如果你不需要:方法应该接受shared_ptr&lt;T&gt; const&amp;

    但也有很多方法不使用它们。

    查看您的代码,您似乎做了很多内存分配,我不禁想知道您是否找不到更好的策略。我必须承认我没有得到完整的数字,所以我可能会直接撞墙但是......

    如果每个对象都有一个所有者,通常代码会简单得多。因此,shared_ptr 应该是万不得已的措施,在您找不到单一所有者时使用。

    无论如何,我们在这里比较的是苹果和橘子,原始代码有问题。您处理了deleting 的内存(很好),但您忘记了这些对象也被程序e1-&gt;setNextEdge(e21) 中的其他点引用,该程序现在保存指向被破坏对象的指针(在一个空闲的内存区域中)。因此,我想如果出现异常,您只需清除整个列表? (或者以某种方式押注未定义的行为来玩得很好)

    因此很难判断性能,因为前者不能很好地从异常中恢复,而后者可以。

    最后:你有没有想过使用intrusive_ptr ?如果您不同步它们(单线程),它可能会给您一些提升(呵呵),并且您将避免shared_ptr 执行的许多操作以及获得参考位置。

    【讨论】:

    • +1 双关语:)。可惜没有 shared_ptr 的线程安全保证,就没有标准的智能指针。以原子方式评估引用计数可能会花费很多(仅根据过去的经验,在 callgrind 中没有很好地考虑)
    • 我建议不要将 const ref 用于共享指针。如果您要获得所有权,请按值获取 shared_ptr 并使用 std::move。否则,只需获取原始指针或引用。 (对 shared_ptr 的 const ref 无论如何都不会处理对象的生命周期)
    【解决方案5】:

    我总是建议使用 std::shared_ptr 而不是依赖手动内存生命周期管理。但是,自动生命周期管理会花费一些成本,但通常并不显着。

    在您的情况下,您注意到 shared_ptr 很重要,正如某些人所说,您应该确保不要不必要地复制共享指针,因为这会强制添加引用/释放。

    但是在后台还有另一个问题:您真的需要首先依赖 new/delete 吗? new/delete 使用 malloc/free,未针对小对象的分配进行调整。

    以前帮助过我很多的图书馆是boost::object_pool

    在某个阶段,我想非常快速地创建图表。节点和边自然是动态分配的,这样做会产生两个成本。

    1. malloc/免费
    2. 内存生命周期管理

    boost:object_pool 有助于降低这两个成本,但代价是不像 malloc/free 那样通用。

    举个例子,假设我们有一个像这样的简单节点:

       struct node
       {
          node * left;
          node * right;
       };
    

    所以我使用 boost::object_pool 来代替 new 分配节点。但是 boost::object_pool 也会跟踪所有分配给它的实例,所以在计算结束时我销毁了 object_pool 并且不需要跟踪每个节点,从而简化了我的代码并提高了性能。

    我做了一些性能测试(我写了自己的池类只是为了好玩,但 bool::object_pool 应该提供相同或更好的性能)。

    创建和销毁 10,000,000 个节点

    1. 普通的新建/删除:2.5 秒
    2. shared_ptr:5 秒
    3. boost::object_pool: 0.15 秒

    因此,如果 boost::object_pool 适合您,它可能有助于显着减少内存分配开销。

    【讨论】:

      【解决方案6】:

      shared_ptr 明显比原始指针慢。这就是为什么只有在您确实需要共享所有权语义时才应该使用它们。

      否则,还有其他几种可用的智能指针类型。 scoped_ptrauto_ptr (C++03) 或 unique_ptr (C++0x) 都有各自的用途。通常,最好的解决方案是不使用任何类型的指针,而是编写自己的 RAII 类。

      shared_ptr 必须递增/递减/读取引用计数器,并且根据实现和实例化方式的不同,引用计数器可能会被单独分配,从而导致潜在的缓存未命中。而且它必须以原子方式访问 ref 计数器,这会增加额外的开销。

      【讨论】:

        【解决方案7】:

        它很慢,因为它用于参考 inc/dec 操作原子指令,因此它非常慢。如果你真的需要 C++ 中的 GC,不要使用幼稚的 RF GC,而使用一些更发达的 RC 策略,或者跟踪 GC。 http://www.hboehm.info/gc/ 非常适合不加速关键任务(但比“智能指针”幼稚 RC 好很多)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-01-30
          • 2010-12-14
          • 1970-01-01
          • 2013-08-10
          • 1970-01-01
          • 2020-11-25
          相关资源
          最近更新 更多