Fortran Coder

标题: 自定义类型的内存占用巨大 [打印本页]

作者: jovan    时间: 2015-12-5 18:53
标题: 自定义类型的内存占用巨大
想要定义一个数据类型,希望能中间包含一个可变大小的数组,写了代码如下
[Fortran] 纯文本查看 复制代码

type cell
integer :: fn
integer, dimension(:), allocatable ::nd
end type cell
type(cell), dimension(:), allocatable ::elem
allocate(elem(10000))

只是给结构体elem赋了内存,维数10000,没有给nd赋内存,但是在进程管理器里查看已经占用了几十倍于10000*4字节的内存,而且再给nd赋内存并赋值后,内存进一步增加。
原以为自定义结构体中不能包含可变大小的数组,于是修改代码为:
[Fortran] 纯文本查看 复制代码
type cell
integer :: fn
integer, dimension(:), pointer ::nd
end type cell
type(cell), dimension(:), allocatable ::elem
allocate(elem(10000))

这样给结构体elem赋内存后,内存占用无异常,但当每一个指针elem(i)%nd指向一个大小不同的数组后,内存占用出现了同样的问题,占用了几十倍于指向的数组的大小,请问如何解决?谢谢

作者: pasuka    时间: 2015-12-5 18:58
完整的代码?
操作系统?
编译器?
编译参数?
啥也没有的话,就算盖茨也没辙
作者: jovan    时间: 2015-12-5 19:43
本帖最后由 jovan 于 2015-12-5 19:45 编辑

操作系统是:Win7编译器:Intel Visual Studio2010
编译环境:x64 Release
完整代码太长了,没法贴,我在一些可疑的地方赋内存之后pause,发现这个结构体一赋内存,内存占用就狂飙


作者: fcode    时间: 2015-12-5 20:24
楼主的问题已在QQ群讨论解决:
1.楼主使用的64位编译器,一个地址占8字节,而非楼主计算的4字节
2.由于Fortran的可分配数组(指针同),除了记录数组的首地址(8字节)之外,还记录数组的维度,每个维度的上限 / 下限 / 间距。因此,这些结构(或称数组描述符 descriptor ) 占用约32字节
作者: pasuka    时间: 2015-12-5 20:44
fcode 发表于 2015-12-5 20:24
楼主的问题已在QQ群讨论解决:
1.楼主使用的64位编译器,一个地址占8字节,而非楼主计算的4字节
2.由于Fort ...

既然如此,还不如在C里面定义这个结构体及其相关操作,然后ISO C BINDING做个interface
有些譬如链表、哈希表啥的,Fortran真的不如C方便与高效
作者: fcode    时间: 2015-12-5 22:59
如果把变量和结构都写入 C 定义,那么相关的计算也必须写入 C,因为可分配数组和fortran指针,都是特殊的数据结构。
fortran的指针包含更丰富的内容,以至于它更安全,不容易越界或指向数组之外。当然,它是以牺牲内存为代价的。
通常来说,较大的数组,但数组个数不多,那么牺牲一点内存来存储这些额外的信息(维度/上下限)是值得的。

像楼主这种1800万个可分配数组,毕竟是较少的情况。
作者: pasuka    时间: 2015-12-6 09:37
fcode 发表于 2015-12-5 22:59
如果把变量和结构都写入 C 定义,那么相关的计算也必须写入 C,因为可分配数组和fortran指针,都是特殊的数 ...

长度是1800w的话,为啥不考虑上SQL数据库或者Hadoop这类大数据处理平台,再不济的话,也得整个out-of-core的模式
直接囫囵吞枣往计算机内存塞那么多信息,实在是费力不讨好的,譬如高清视频动辄20、30G,远超过内存容量,但是播放的时候,只会读入一段数据
lz应该去看看数据库以及大数据处理相关的现成软件包或框架
作者: jovan    时间: 2015-12-6 10:08
pasuka 发表于 2015-12-6 09:37
长度是1800w的话,为啥不考虑上SQL数据库或者Hadoop这类大数据处理平台,再不济的话,也得整个out-of-cor ...

这个是流体计算网格的前处理程序,以前处理小网格没有啥问题,现在算大网格出了这问题,回头我换个平台试试看,要还是不行就考虑改程序,数据库完全不懂...
作者: fcode    时间: 2015-12-6 10:11
从数据库取数,必然比从内存取数会慢很多

时间(执行效率)和空间(内存大小)总是不可兼得,两难相权取其轻吧。
作者: pasuka    时间: 2015-12-6 10:14
jovan 发表于 2015-12-6 10:08
这个是流体计算网格的前处理程序,以前处理小网格没有啥问题,现在算大网格出了这问题,回头我换个平台试 ...

CFD计算的话,不妨去OpenFoam的论坛或者mailing-list去问问看,肯定有成熟的解决办法
作者: 好小爱新    时间: 2015-12-7 12:18
虽然已经结贴,但我还是要说一下,楼主切不可以C的编程思想来写Fortran程序。要知道,C的数组是没有Shape信息的,面Fortran却有。那么一个数组需要多少空间存这些Shape信息呢?至少我们需要:
数组起始地址;(一个字长)
维度;(4字节)
每个维度又至少会有:
上标;(4字节)
下标;(4字节)
间隙:(4字节)
内存对齐保留处(4字节)—这部分可选,但一般都会有。
部分编译器实现还会在维度+1的地方有全0填充防侧漏。
这样一来,如果您的单个数组很小,但数组的数量却非常多,那内存占用就远远会超出你的预期。

对于一个计算问题,我们Fortran一般都是用单一数组解决,而不使用如此松散的方式存储。因为,只有批量操作才能显现Fortran计算的优越性,并且也便于编译器做优化。
作者: jovan    时间: 2015-12-9 11:47
是这样的,以之前的数据结构写的话,多余的内存占用不可避免,而且比数据本身需要占用的内存还大,造成了很大的浪费,谢谢你的提醒




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2