C 大型三维阵列的动态分配
我正在做一个项目,我需要创建一个三维阵列,一些二维和一维阵列。3D阵列表示空间中的离散坐标,我需要很多点来解决我的问题。阵列大小约为2000*2000*2000。我需要在这些数组中存储“double”值。有人能提出一个有效的方案来实现这一点吗 提前谢谢C 大型三维阵列的动态分配,c,multidimensional-array,C,Multidimensional Array,我正在做一个项目,我需要创建一个三维阵列,一些二维和一维阵列。3D阵列表示空间中的离散坐标,我需要很多点来解决我的问题。阵列大小约为2000*2000*2000。我需要在这些数组中存储“double”值。有人能提出一个有效的方案来实现这一点吗 提前谢谢 /*********************************************************** * Copyright Univ. of Texas M.D. Anderson Cancer Center * 1
/***********************************************************
* Copyright Univ. of Texas M.D. Anderson Cancer Center
* 1992.
*
* Some routines modified from Numerical Recipes in C,
* including error report, array or matrix declaration
* and releasing.
****/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <malloc.h>
/***********************************************************
* Report error message to stderr, then exit the program
* with signal 1.
****/
void nrerror(char error_text[])
{
fprintf(stderr,"%s\n",error_text);
fprintf(stderr,"...now exiting to system...\n");
exit(1);
}
/***********************************************************
* Allocate an array with index from nl to nh inclusive.
*
* Original matrix and vector from Numerical Recipes in C
* don't initialize the elements to zero. This will
* be accomplished by the following functions.
****/
double *AllocVector(short nl, short nh)
{
double *v;
short i;
v=(double *)malloc((unsigned) (nh-nl+1)*sizeof(double));
if (!v) nrerror("allocation failure in vector()");
v -= nl;
for(i=nl;i<=nh;i++) v[i] = 0.0; /* init. */
return v;
}
/***********************************************************
* Allocate a matrix with row index from nrl to nrh
* inclusive, and column index from ncl to nch
* inclusive.
****/
double **AllocMatrix(short nrl,short nrh,
short ncl,short nch)
{
short i,j;
double **m;
m=(double **) malloc((unsigned) (nrh-nrl+1)
*sizeof(double*));
if (!m) nrerror("allocation failure 1 in matrix()");
m -= nrl;
for(i=nrl;i<=nrh;i++) {
m[i]=(double *) malloc((unsigned) (nch-ncl+1)
*sizeof(double));
if (!m[i]) nrerror("allocation failure 2 in matrix()");
m[i] -= ncl;
}
for(i=nrl;i<=nrh;i++)
for(j=ncl;j<=nch;j++) m[i][j] = 0.0;
return m;
}
/***********************************************************
* Allocate a 3D array with x index from nxl to nxh
* inclusive, y index from nyl to nyh and z index from nzl to nzh
* inclusive.
****/
double ***Alloc3D(short nxl,short nxh,
short nyl,short nyh,
short nzl, short nzh)
{
double ***t;
short i,j,k;
t=(double ***) malloc((unsigned) (nxh-nxl+1)*sizeof(double **));
if (!t) nrerror("allocation failure 1 in matrix()");
t -= nxl;
for(i=nxl;i<=nxh;i++) {
t[i]=(double **) malloc((unsigned) (nyh-nyl+1)*sizeof(double *));
if (!t[i]) nrerror("allocation failure 2 in matrix()");
t[i] -= nyl;
for(j=nyl;j<=nyh;j++) {
t[i][j]=(double *) malloc((unsigned) (nzh-nzl+1)*sizeof(double));
if (!t[i][j]) nrerror("allocation failure 3 in matrix()");
t[i][j] -= nzl;}
}
for(i=nxl;i<=nxh;i++)
for(j=nyl;j<=nyh;j++)
for(k=nzl; k<=nzh;k++) t[i][j][k] = 0.0;
return t;
}
/***********************************************************
*Index to 3D array.
****/
long index(int x, int y, int z, int Size)
{
return (Size*Size*x + Size*y + z);
}
/***********************************************************
* Release the memory.
****/
void FreeVector(double *v,short nl,short nh)
{
free((char*) (v+nl));
}
/***********************************************************
* Release the memory.
****/
void FreeMatrix(double **m,short nrl,short nrh,
short ncl,short nch)
{
short i;
for(i=nrh;i>=nrl;i--) free((char*) (m[i]+ncl));
free((char*) (m+nrl));
}
/***********************************************************
* Release the memory.
****/
void Free3D(double ***t,short nxl,short nxh,
short nyl,short nyh, short nzl, short nzh)
{
short i,j;
for(i=nxh;i>=nxl;i--)
{for(j=nyl;j>=nyl;j--) free((char*) (t[i][j]+nzl));
free((char*) (t[i]+nyl));
}
free((char*) (t+nxl));
}
***********************************************************************************
void InitOutputData(InputStruct In_Parm, OutStruct * Out_Ptr)
{
short nz = In_Parm.nz;
short nr = In_Parm.nr;
short na = In_Parm.na;
short nl = In_Parm.num_layers;
short size = nr/2*nr/2*nz;
/* remember to use nl+2 because of 2 for ambient. */
if(nz<=0 || nr<=0 || na<=0 || nl<=0)
nrerror("Wrong grid parameters.\n");
/* Init pure numbers. */
Out_Ptr->Rsp = 0.0;
Out_Ptr->Rd = 0.0;
Out_Ptr->A = 0.0;
Out_Ptr->Tt = 0.0;
/* Allocate the arrays and the matrices. */
//Out_Ptr->Rd_ra = AllocMatrix(0,nr-1,0,na-1);
//Out_Ptr->Rd_r = AllocVector(0,nr-1);
//Out_Ptr->Rd_a = AllocVector(0,na-1);
Out_Ptr->A_xyz1 = AllocVector(0,size-1);
Out_Ptr->A_xyz2 = AllocVector(0,size-1);
Out_Ptr->A_xyz3 = AllocVector(0,size-1);
Out_Ptr->A_xyz4 = AllocVector(0,size-1);
Out_Ptr->A_xz = AllocMatrix(0,nr-1,0,nz-1);
Out_Ptr->A_z = AllocVector(0,nz-1);
Out_Ptr->A_l = AllocVector(0,nl+1);
Out_Ptr->Tt_ra = AllocMatrix(0,nr-1,0,na-1);
Out_Ptr->Tt_r = AllocVector(0,nr-1);
Out_Ptr->Tt_a = AllocVector(0,na-1);
}
/***********************************************************
*德克萨斯大学安德森癌症中心版权所有
* 1992.
*
*从C中的数字公式修改的一些例程,
*包括错误报告、数组或矩阵声明
*然后释放。
****/
#包括
#包括
#包括
#包括
/***********************************************************
*向stderr报告错误消息,然后退出程序
*有信号1。
****/
无效nError(字符错误\u文本[])
{
fprintf(标准,“%s\n”,错误\u文本);
fprintf(stderr,“…正在退出系统…\n”);
出口(1);
}
/***********************************************************
*分配索引从nl到nh(含nl)的数组。
*
*C中数值公式的原始矩阵和向量
*不要将元素初始化为零。这将
*可通过以下功能完成。
****/
双*AllocVector(短nl,短nh)
{
双*v;
短i;
v=(双*)malloc((未签名)(nh nl+1)*sizeof(双));
如果(!v)nError(“向量()中的分配失败”);
v-=nl;
对于(i=nl;iA_xyz3=AllocVector(0,尺寸-1);
Out_Ptr->A_xyz4=AllocVector(0,大小为1);
Out_Ptr->A_xz=AllocMatrix(0,nr-1,0,nz-1);
Out_Ptr->A_z=AllocVector(0,nz-1);
Out_Ptr->A_l=AllocVector(0,nl+1);
Out_Ptr->Tt_ra=AllocMatrix(0,nr-1,0,na-1);
Out_Ptr->Tt_r=AllocVector(0,nr-1);
Out_Ptr->Tt_a=AllocVector(0,na-1);
}
上面是分配数组的代码和调用它们的函数。当大小超过大约7000时,失败的调用是'Out_Ptr->A_xyz1=AllocVector(0,size-1);'。如果它们是固定大小(或至少是固定的最大大小)在运行时,如果它们比物理RAM大,那么您也可以使用内存映射文件。访问速度至少与RAM+swap一样快,您可以免费将数据序列化到磁盘。您还可以映射总体上大于您的地址空间的映射文件的区域(即窗口)视图
如果你需要大量的细胞,因为你需要一些区域的高细节,但不是均匀的,你可以考虑八叉树。然后你可以在某些部分存储渐进的精细分辨率,你可以重新排序以优化对3D附近区域的访问-这在CFD或医学成像方面非常普遍。这是一个完美的mmap使用案例!您的阵列是64 GB-太大了,无法一次装入RAM。幸运的是,我们可以强制内核为我们完成所有繁重的工作
以下是一些(公认未经测试的)代码:#包括
#包括
#包括
#包括
#包括
#包括
#定义数组大小((关闭)2000*2000*2000*8)
静态内联off_t idx(off_t x、off_t y、off_t z)
{
返回2000*2000*x+2000*y+z;
}
int main()
{
int fd=open(“my_-mage_-array.dat”,O_-RDWR | O|u-CREAT | O|u-TRUNC);
//我们必须写入文件的末尾,以便正确设置大小。
lseek(fd,数组大小-1,搜索集);
写(fd,“,1);
double*my_-mage_-array=mmap(NULL,数组大小,保护读取,保护写入,映射共享,fd,0);
//现在玩阵列!
my_巨型_数组[idx(4,7,9)]=12;
my_-Great_array[idx(0,0,0)]=my_-Great_array[idx(4,7,9)]*2;
//把它关起来,别漏了你的fd!
munmap(我的大数组,数组大小);
关闭(fd);
移除(“my_-ground_-array.dat”);
返回0;
}
它将是一个稀疏数组吗?坐标是否表示一个规则的网格?即,您必须存储值,或者在需要时可以从一个矩形范围内的网格间距计算值?您需要以顺序或随机访问的方式访问数组吗?您可以存储一个大文件的部分以存储值。不能进行随机访问尽管如此,还是要访问。不要用自动作用域声明,即在函数中声明。堆栈溢出会发生。您是否意识到您正在尝试分配2000x2000x2000x8=64 GB?难怪内存不足!malloc无法分配如此大的块。我从未使用过mmap()。让我试着回答一下。非常感谢。pitc,如果你在32位平台上,2000^3比地址空间大,因此你要么单独处理平面/行/列,要么使用映射视图,要么切换到64位!是的,我得到了这一部分,但我甚至无法使用malloc()分配100*100*100数组.现在,我认为问题不在于malloc。我将把我的代码添加到文章中。问题在于malloc需要一个这么大的未中断内存块!您需要对每个2d平面(甚至可能是每一行)进行malloc分别创建一个数组。这样maloc就可以为100x100块内存找到空间。我也尝试过这样做。看看Alloc 3D。当我尝试使用该函数时也会遇到同样的问题。如果我需要将映射保持打开直到代码结束怎么办。现在的运行时间大约是50小时。可以吗?或者我需要关闭它并在每次写入时打开它。你知道吗可以随时关闭它。50小时就可以了。内核管理所有内存->磁盘活动,我假设是LRU缓存。@pitc-mmap的另一个优点是,每隔10-15分钟将其刷新到磁盘,并序列化您需要的任何其他数据值。然后,如果出现故障,您可以编写代码,从保存的指针恢复如果我想从另一个函数调用创建过程,在其他函数通过指针向映射添加数据时保持映射活动,然后使用另一个函数关闭映射,那么如何创建映射?
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define ARRAY_SIZE ((off_t)2000*2000*2000*8)
static inline off_t idx(off_t x, off_t y, off_t z)
{
return 2000*2000*x + 2000*y + z;
}
int main()
{
int fd = open("my_huge_array.dat", O_RDWR | O_CREAT | O_TRUNC);
// We have to write to the end of the file for the size to be set properly.
lseek(fd, ARRAY_SIZE - 1, SEEK_SET);
write(fd, "", 1);
double* my_huge_array = mmap(NULL, ARRAY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// Now play with the array!
my_huge_array[idx(4, 7, 9)] = 12;
my_huge_array[idx(0, 0, 0)] = my_huge_array[idx(4, 7, 9)] * 2;
// Close it up. Don't leak your fd's!
munmap(my_huge_array, ARRAY_SIZE);
close(fd);
remove("my_huge_array.dat");
return 0;
}