【问题标题】:Good C++ array class for dealing with large arrays of data in a fast and memory efficient way?以快速和内存高效的方式处理大型数据数组的良好 C++ 数组类?
【发布时间】:2011-01-29 04:47:02
【问题描述】:

previous question relating to heap usage restrictions 开始,我正在寻找一个良好的标准 C++ 类,用于以一种既节省内存又提高速度的方式处理大型数据数组。我一直在使用单个 malloc/HealAlloc 分配数组,但在多次尝试使用各种调用后,不断遇到堆碎片。因此,除了移植到 64 位之外,我得出的结论是使用一种机制,该机制允许我拥有一个跨越多个较小内存片段的大型数组。我不希望每个元素分配一个 alloc,因为这样内存效率非常低,因此计划编写一个覆盖 [] 运算符的类并根据索引选择适当的元素。是否已经有一个像样的课程可以做到这一点,还是我最好自己动手?

根据我的理解,以及一些googling,理论上一个 32 位的 Windows 进程应该能够寻址高达 2GB。现在假设我安装了 2GB,并且各种其他进程和服务占用了大约 400MB,您认为我的程序可以合理地期望从堆中获得多少可用内存?

我目前正在使用各种风格的 Visual C++。

编辑根据 Poita 的帖子,我尝试了 std::deque,在 VS2008 上使用以下测试;

#include <deque>
using namespace std;
struct V    
{
    double  data[11];
};

struct T
{
    long    data[8];    
};


void    dequeTest()
{
    deque<V> VQ;
    deque<T> TQ;

    V defV;
    T defT;

    VQ.resize(4000000,defV);
    TQ.resize(8000000,defT);
}

上述数据的总内存为 608MB,如果我使用直接 malloc 或 HeapAlloc,则需要

我想是时候编写我自己的大数组类了。

第二次编辑:分配较小的金额立即使用以下内容产生 1.875GB;

#define TenMB 1024*1024*10

void    SmallerAllocs()
{

    size_t Total = 0;
    LPVOID  p[200];
    for (int i = 0; i < 200; i++)
    {
        p[i] = malloc(TenMB);
        if (p[i])
            Total += TenMB; else
            break;
    }
    CString Msg;
    Msg.Format("Allocated %0.3lfGB",Total/(1024.0*1024.0*1024.0));
    AfxMessageBox(Msg,MB_OK);
}

最终编辑 我决定接受 Poita 的帖子和各种 cmet紧随其后的 cmets。这应该很容易通过 O(1) 随机元素访问来实现,基于每个块的固定数量的元素,这正是我所需要的。感谢大家的反馈!

【问题讨论】:

  • 我希望这些“口味”都不是VC6.0
  • 虽然我还有 VC6.0,但将它用于一些事情,而不是任何接近发布阶段的事情。主要是 VS2008,一些 VS2003,和一些 EVC++ 4.0,这就是为什么我也维护一个 VC6.0。
  • 一个 32 位的 windows 程序可以分配超过 2GB 的内存,你只是不能同时映射所有的内存。 - blogs.msdn.com/oldnewthing/archive/2004/08/10/211890.aspx

标签: c++ arrays visual-c++


【解决方案1】:

从您的程序的角度来看,无论系统中发生什么其他情况,您在启动时始终有 2GB 可用空间。我不相信 Windows 提供了一种方法来检测您是否有内存被分页到磁盘。就您的数据结构而言,听起来您在描述类似于在 STL 中实现双端队列的方式。

【讨论】:

【解决方案2】:

您是否尝试过使用std::deque?与使用一个巨大堆分配的std::vector 不同,deque 通常以小块分配,但仍通过operator[] 提供摊销的常数时间索引。

【讨论】:

  • 我会看看双端队列的实现,但我会担心这些块有多小。我正在处理数百万个相对较小的结构,因此任何基于每个项目单独分配内存的实现都可能导致内存效率低下。
  • 我不知道它使用什么策略来调整大小,但肯定远远超过 1。我怀疑内存效率低下会超过 10%,我希望它是
  • 在阅读了 std::deque 之后,特别是关于使用分配器的内容,我找不到任何说明它不会尝试在单个连续块中分配所有内存的内容。请参阅cplusplus.com/reference/std/memory/allocator 换句话说,我找不到任何建议向双端队列添加 1GB 数据比使用 HeapAlloc 做同样的事情更有可能成功。您是否有任何参考资料表明双端队列将使用多个堆分配来处理大量数据,如果是,它如何对它们进行分段?
  • @Shane,它来自这样一个事实,即双端队列需要 O(1) 时间来执行 push_front 以及执行 operator[],而实现这一点的唯一方法是在块中分配。
  • 嗯。自己将其放入答案中可能是值得的。我过去曾为自己的问题这样做过。我很确定它是洁净的。
【解决方案3】:

这个数组到底有多稀疏?如果其中有大量空(未使用)空间,您可能需要采取另一种方法。 answer to this question 建议使用 stl 映射。

如果它不是稀疏的(如 cmets 中所述),由于您在 Windows 上运行,您可能会考虑使用memory-mapped file。尽管您的操作系统可能是 32 位的,但您的文件系统不是。这当然意味着会进行交换,这可能会比你真正将整个该死的东西放在 RAM 中要慢很多。

另外,您真的应该考虑将系统的 RAM 调到最大(我相信在 32 位 Windows 上为 3GB),看看是否可以解决问题。这应该只花费你大约 100 美元,而且你在工时上的花费远远超过了担心这一点的成本。

【讨论】:

  • 很遗憾,根本没有未使用的空间。有问题的数据是一个 TIN 网络,由 3d 坐标和将它们连接在一起的三角形组成,共同代表一个大的不规则表面。无论如何感谢您的链接,可能在其他地方很有用。
  • 已安装 2GB != 2GB 物理内存可用。即使安装了 4GB,如果你有一个大内存显卡,你安装的容量也可能不超过 2.5GB(如果你正在做 3D 工作,那么这是一个明显的可能性)。亲自确保您已安装 4+GB 和 64 位操作系统。
  • @graham - 他已经说过他正在使用 32 位操作系统,并询问他除了升级到 64 位还能做什么。这就是为什么我建议提高到 3GB。话虽如此,我同意使用 64 位操作系统可能是一个很好(而且相对便宜)的解决方案。
  • 移植到 64 位肯定会在今年晚些时候出现,但这只是解决方案的一部分。我们有很多使用 32 位笔记本电脑的客户,它们不太可能很快升级,而一个好的 32 位解决方案可以解决他们当前硬件的问题,具有真正的价值。
  • Re:“数据......是...... 3d坐标......三角形......共同代表一个大的不规则表面”,你有什么理由不使用三角表面图书馆?其中有几个。
【解决方案4】:

std::deque 完全符合您的描述,但通常以操作系统页面大小为粒度(即,它分配的块通常为 4 kB)。

如果您对 deque 的默认性能不满意,您可以编写一个自定义分配器来抓取更大的块——也就是说,一次获得 1 MB 或更多。

正如其他人所说,您的进程的虚拟地址空间完全独立于所有其他进程,因此无论系统中发生什么其他事情,您都可以寻址 2GB。操作系统将根据需要将内存页面交换到磁盘或从磁盘交换,以适应已安装内存量和所有竞争它的进程的限制。这将在 4 kB 页面大小时发生,与您的块有多大无关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多