C++ 存储大量数据的数据结构?

C++ 存储大量数据的数据结构?,c++,memory,data-structures,dynamic-memory-allocation,C++,Memory,Data Structures,Dynamic Memory Allocation,在我的应用程序中,我必须从一组图像(MRC图像)中加载volumedata,并将像素数据保存在内存中(图像是灰度的,因此每个像素一个字节) 我的开发环境是QT framework、Windows的MinGW和Linux的GCC 目前,我使用一个简单的数据结构将volumedata存储为: unsigned char *volumeData; 然后做一个巨大的分配,如下所示 volumeData=new unsigned char[imageXsize * imageYsize * numofI

在我的应用程序中,我必须从一组图像(MRC图像)中加载volumedata,并将像素数据保存在内存中(图像是灰度的,因此每个像素一个字节)

我的开发环境是QT framework、Windows的MinGW和Linux的GCC

目前,我使用一个简单的数据结构将volumedata存储为:

unsigned char *volumeData;
然后做一个巨大的分配,如下所示

volumeData=new unsigned char[imageXsize * imageYsize * numofImages];
以下是访问给定平面中图像数据的重要方法,例如

unsigned char* getXYPlaneSlice(int z_value);
unsigned char* getYZPlaneSlice(int x_value);
unsigned char* getZXPlaneSlice(int y_value);
通过我简单的数据结构,很容易实现上述方法

但我们将来可能需要将卷大小调整为2000x2000x1000(~3.7Gb),而当前的数据结构将无法处理如此庞大的数据

  • 如何避免碎片化?现在,即使有1000x1000x200数据,应用程序崩溃也会导致错误的分配。 为此更改数据结构的最佳方法是什么?我应该使用类似链表的东西,每个区块大小为100mb

  • 此外,用户应该能够对体积数据执行一些图像处理过滤器,还应该能够重置为原始像素值。 也就是说,我应该保留两份卷数据的副本。 与当前的实现类似

    无符号字符*volumeDataOriginal

    无符号字符*volumeDataCurrent

  • 因此,对于2000x2000x1000数据范围,它将利用大约8Gb(每个卷4Gb)。 但在Win32中,地址空间是4GB。如何解决这个问题?我应该使用64位应用程序吗

    编辑: 这是我的应用程序的快照

    基本上,我加载体积数据(来自图像集、来自MRC格式等)并在不同的平面查看器中显示它们(XY、YX、YZ。图像显示XY平面查看器)。我需要保留以上3种数据访问方法以在特定平面中显示图像。使用滑条用户可以更改要在选定平面中显示的图像)


    提前感谢。

    64位可能是处理此问题的最简单方法。。。让操作系统在使用页面时出错。否则,在不了解数据访问模式的情况下,很难给出很多建议。如果您定期扫描图像以查找相同像素坐标下的值,那么说拥有指向图像的指针以按需保存和重新加载是毫无意义的


    对于撤消数据,您可以按照建议保留完整备份副本,也可以尝试执行撤消操作,以查看所做的更改并负责找到有效的实现。例如,如果您刚刚翻转了位,那么这是非破坏性的,您只需要对同一位翻转操作使用一个函子来撤消更改。如果将所有像素设置为同一色调是一个常见操作(例如填充、清除),那么您可以使用一个布尔值和一个像素对图像状态进行编码,并使用完整的缓冲区进行撤消。

    我想您应该看看。这是一种二进制格式,用于存储从望远镜、物理实验和基因测序机等设备收集的大量数据。使用这种方法的好处很多,但有三个直接的想法:(1)经过测试,(2)支持hyperslab选择,以及(3)免费获得压缩


    有C/C++、java、python和matlab库可用

    > P> >一种选择,我认为是内存映射,而不是映射所有图像,保持一个链接列表的图像是懒惰加载。当过滤器在图像列表中工作时,根据需要加载。在加载阶段,映射一个大小相同的匿名(或某个固定临时文件)块,并将映像复制到该块作为备份。在应用筛选器时,只需备份到此副本。如上@Tony所述,64位是您的最佳选择,对于多平台内存映射文件,请查看boost interprocess。

    您可以使用内存映射文件管理内存有限的大型数据集。但是,如果文件大小为4GB,则建议使用64位。boost项目有一个很好的多平台内存映射库,它的性能非常接近您所需要的

    http://www.boost.org/doc/libs/1_44_0/libs/iostreams/doc/classes/mapped_file.html 让你开始。下面是一些示例代码--

    #包括
    boost::iostreams::映射的\u文件\u源输入\u源;
    输入_source.open(std::string(argv[1]);
    const char*data=input_source.data();
    long size=input_source.size();
    输入_source.close();
    
    谢谢,
    Nathan

    您可以使用两级结构: 指向单个图像或(更好的)一组图像的指针数组。 因此,您可以将20个图像保存在一个内存块中,并将指向20个图像块的指针放入数组中。 在进行随机访问时,这仍然很快(与链表相比)

    然后,您可以实现一个简单的分页算法:首先,数组中的所有指针都是空的。首次访问图像块时,将该块的20个图像加载到内存中,并将指针写入数组。 下次访问这些图像时不会加载任何内容

    如果由于加载和加载了许多图像块而导致内存不足,则可以删除使用最少的图像块(应在指针旁边添加第二个字段,在该字段中输入每次加载图像块时计数的计数器值)。计数器最低的图像块是使用最少的图像块,可以删除(内存被重新用于新块,指针设置为NULL)。

    请查看。我不是it专家,但从its和,它允许您自然地将数据映射到3D(+1D用于时间/版本控制)数组中,如下所示:

    CREATE ARRAY Pixels [
        x INT,
        y INT,
        z INT,
        version INT
    ] (
        pixel INT
    );
    
    要实现查询,请执行以下操作:

    Slice (Pixels, z = 3, version = 1);
    
    为了避免在仅更改部分数据时重复数据,不需要为版本1填充整个阵列,因为SciDB支持稀疏阵列。然后,当需要加载最新数据时,可以使用
    version=0
    加载以获取旧版本,然后
    Slice (Pixels, z = 3, version = 1);