主题:请教一个很奇怪的问题(编译后的exe会变大)
blitheli
[专家分:440] 发布于 2010-05-20 22:29:00
程序代码见下,很简单的代码。我用的编译器是ivf11.060
我发现当cc数组取值不同时,编译后的exe文件大小会相差很大,百思不得其解,请教原因。
module ta
implicit none
!-----------------------------
! 自定义指针数组
type:: MT_array
real(8),pointer:: MT(:)=>null()
end type MT_array
!-----------------------------
! 自定义数据类型
type tp1
!若将下面两句任一句注释掉,则不会出现编译后的exe很大的情况
type(MT_array):: ar
real(8):: cc(500,20000)
end type tp1
end module ta
module tb
use ta
implicit none
public
type(tp1):: t11 !若将此处换成指针,则不会出现编译后的exe文件很大的问题
end module tb
!-------------------------------------
program Console1
use tb
implicit none
! Body of Console1
print *, 'Hello World'
end program Console1
回复列表 (共6个回复)
沙发
asymptotic [专家分:16630] 发布于 2010-05-20 23:24:00
If an object of a type for which component-initialization is specified appears in the specification-part of a MODULE and does not have ALLOCATABLE or POINTER attribute, the object shall have the SAVE attribute.
板凳
asymptotic [专家分:16630] 发布于 2010-05-20 23:43:00
在 IVF11.1 中,我并未发现 exe 文件有何变化。
3 楼
blitheli [专家分:440] 发布于 2010-05-22 22:00:00
我用的11.060的IVF,确实出现这种情况啊。哪位大侠再试一下啊?多谢
4 楼
臭石头雪球 [专家分:23030] 发布于 2010-05-23 23:37:00
在程序中使用了大量的静态数组,最后的EXE就可能会很大。
我的 IVF 也发生了这样的问题。
500*20000*8 大概 = 76*1024*1024,也就是 76MB。
对最后的Exe进行分析,最大的区段是 .data 段,也就是数据段。数据段内的冗余数据很多,大多数压缩程序(UPX,ASPack)都可以压缩为正常的尺寸。
至于静态数组何时放入 .data 段,是否占有RAW大小,何时放入 Heap 进行动态分配?这个问题是由不同编译器而决定的。个人认为研究这个问题没有多大意义。
type(tp1):: t11 定义为指针,则不占有大量空间,因为指针在内存中只是一个 Address 或者 Descriptor。而一旦分配指针,则内存中会申请76MB的内存(注意这里的内存并不由EXE镜像映射,因此EXE文件大小正常)。
注释掉 real(8):: cc(500,20000) 由于静态数组不存在,因此EXE尺寸正常,这个很容易理解。
我们知道,EXE加载后,PE加载器从EXE结构里对文件进行内存映射。某个区段,比如 .data,其 RAW 大小被映射为虚拟大小。超出RAW的部分,映射为 00
因此,对于全部是 00 的 .data 数据,编译器可以不储存在RAW大小内,利用映射内存自动填充 00
所以,当注释掉 type(MT_array):: ar 整个结构体初始值都是 00,编译器就不会在EXE文件的 .data 段储存 76MB 的数据。
而当存在 type(MT_array):: ar 时,其内容不为空,编译器不得不在 EXE 文件里储存初始。不得不使用文件映射到内存。
空值时的EXE结构:
No | 名称 | 虚拟大小 | 虚拟偏移量 | 原始大小 | 原始偏移量 | 特性 |
01 | .text | 00062183 | 00001000 | 00063000 | 00001000 | 60000020 |
02 | .text1 | 000000D0 | 00064000 | 00001000 | 00064000 | 60000020 |
03 | .rdata | 0000F1EC | 00065000 | 00010000 | 00065000 | 40000040 |
04 | .data | 04C5A35C | 00075000 | [color=red]00004000[/color] | 00075000 | C0000040 |
05 | .data1 | 00000020 | 04CD0000 | 00001000 | 00079000 | C0000040 |
非空值时的EXE结构:
No | 名称 | 虚拟大小 | 虚拟偏移量 | 原始大小 | 原始偏移量 | 特性 |
01 | .text | 00062183 | 00001000 | 00063000 | 00001000 | 60000020 |
02 | .text1 | 000000D0 | 00064000 | 00001000 | 00064000 | 60000020 |
03 | .rdata | 0000F1EC | 00065000 | 00010000 | 00065000 | 40000040 |
04 | .data | 04C5A37C | 00075000 | [color=red]04C4F000[/color] | 00075000 | C0000040 |
05 | .data1 | 00000020 | 04CD0000 | 00001000 | 04CC4000 | C0000040 |
注意,这样的测试仅仅是针对某个编译器的。并不是 Fortran 自身的问题。
尽管两个EXE的尺寸相差很大,但运行后占有的内存,是差不多的。因为前者虽然文件小,加载到内存后,.data 段依然映射了 76MB 的大小!!!
当然了,相对而言,前者速度快一些,因为后者从文件中映射,读取硬盘需要一定的时间。
5 楼
blitheli [专家分:440] 发布于 2010-05-24 20:56:00
谢谢楼上的指导。
但是,如此说来,这样的数据结构岂不是不能用了,要不然 exe文件很大的话不是很麻烦。
6 楼
臭石头雪球 [专家分:23030] 发布于 2010-05-25 08:18:00
[quote]谢谢楼上的指导。
但是,如此说来,这样的数据结构岂不是不能用了,要不然 exe文件很大的话不是很麻烦。[/quote]
实际上,有很多方式可以避免这样的问题。只不过IVF没有做。
你可以继续使用这样的数据结构,有很多压缩工具可以对EXE进行压缩,比如 UPX,ASPack 等,你上baidu去google一下....这样的工具压缩以后还可以正常执行,丝毫不影响EXE工作。
对于这个问题,由于压缩了空间,更会使得EXE加载更快。
而其他一些编译器,比如Ftn95,不管哪种方式,产生的EXE都非常小巧。我没有具体分析原因,可能是由于Ftn95内核都在一个DLL里,或者使用了BSS重定向。
所以,这是 IVF 的不足,而不是数据结构的问题。因为大多数情况下,我们不会傻傻的储存这样冗余的数据。
我来回复