在 Linux on POWER 上利用透明大内存页(3)执行体内的段
 
- UID
- 1066743
|

在 Linux on POWER 上利用透明大内存页(3)执行体内的段
开始之前,我们先来看看在所生成的执行体中包含的段。我会通过一个简单的 C 程序加以演示。在如下的示例中,我将声明一个大型的未初始化的数组和一个大型的已经初始化了的数组。
显示了称为 sections.c 的源文件。
清单 1. sections.c 源文件1
2
3
4
5
6
7
8
9
10
| #define ELEMENTS 1024*1024
static double bss_array[ELEMENTS];
static double data_array[ELEMENTS] = {5.0};
int main() {
int i;
for (i = 1; i < ELEMENTS; i++) {
bss_array = data_array;
}
}
|
bss 数组和 data 数组的主要区别很容易在下一步所生成的执行体中看出来。bss 和 data 数组的区别如下:
- bss 数组 —— 此数组是未初始化的数据,保存在执行体的 .bss 段。此段不占用执行体的任何空间。
- data 数组 —— 此数组是已初始化的数据(非零),必须保存在执行体本身的 .data 段。在上述情况下,每个双精度是 8 字节,所以要占用执行体中 8*1024*1024 (8MB) 字节的空间。
要查看执行体中的这些特性,只需编译此程序,然后用 readelf 命令显示段信息,如 所示。
清单 2. C 程序中的段信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # cc sections.c -o sections
# ls -l sections
-rwxr-xr-x 1 root root 8400154 2006-12-03 18:52 sections
# readelf -S sections
There are 36 section headers, starting at offset 0x8012cc:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 10000154 000154 00000d 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 10000164 000164 000020 00 A 0 0 4
...
[12] .text PROGBITS 100002f0 0002f0 0005b0 00 AX 0 0 16
[13] .fini PROGBITS 100008a0 0008a0 000038 00 AX 0 0 4
...
[23] .plt PROGBITS 10010a28 000a28 000008 00 WA 0 0 4
[24] .data PROGBITS 10010a30 000a30 800008 00 WA 0 0 8
[25] .bss NOBITS 10810a38 800a38 800008 00 WA 0 0 8
[26] .comment PROGBITS 00000000 800a38 0000d9 00 0 0 1
...
|
在 所示的输出中,观察如下内容:
- 执行体的大小 —— 执行体的大小是 8400154,对于较小的程序来说,这明显有些过大。
- .text —— 文本是编译器生成的可执行指令。对于大型程序而言,可引导 libhugetlbfs 将此段加载进 16MB 大内存页。在本例中,可执行文本的大小只有 5b0(hex) 字节,所以不应将其放至 16MB 大内存页。
- .data —— 程序中的数据段的大小为 800008(hex) 字节 。这与所声明的 8MB data 数组是相符的。初始化的数据是执行体本身的一部分,而这会使执行体变得很大,认识到这一点十分重要。通过偏移量则可以很容易看出这一点。数据段从偏移量 000a30 开始,而下一个段则开始于偏移量 800a38。
- .bss —— 程序中的 .bss 段的大小也为 800008(hex) 字节,但它并不占用执行体中的空间,.bss 段以及下一个段的开始偏移量不会更改,两个都是 800a38(hex)。
将 data 数组更改为 bss 数组为了演示编译器是如何处理数组初值的,可以将 data_array 的初值从 5.0 更改为 0.0,注意到它现在变成了执行体中的 .bss 段,如下所示:
1
2
3
4
5
| ...
#define ELEMENTS 1024*1024
static double bss_array[ELEMENTS];
static double data_array[ELEMENTS] = {0.0}; <---- zero'ing makes this a .bss array
...
|
如果将 data_array 初始化为零,编译器会将其视为 .bss 段。需要重新编译,结果如 所示。请看如下的 .data 段。
清单 3. 现在在 .bss 段中的 .data 段1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # cc sections.c -o sections
# ls -l sections
-rwxr-xr-x 1 root root 11546 2006-12-03 18:54 sections
# readelf -S sections
There are 36 section headers, starting at offset 0x12cc:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 10000154 000154 00000d 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 10000164 000164 000020 00 A 0 0 4
...
[12] .text PROGBITS 100002f0 0002f0 0005b0 00 AX 0 0 16
[13] .fini PROGBITS 100008a0 0008a0 000038 00 AX 0 0 4
...
[23] .plt PROGBITS 10010a28 000a28 000008 00 WA 0 0 4
[24] .data PROGBITS 10010a30 000a30 000008 00 WA 0 0 4 \
<----- No longer a data array
[25] .bss NOBITS 10010a38 000a38 1000008 00 WA 0 0 8 \
<----- Now twice the size
[26] .comment PROGBITS 00000000 000a38 0000d9 00 0 0 1
...
|
注意 size 列以及与大小相关的偏移量。所发生的更改描述如下:
- 执行体的大小 —— 执行体的大小现在只有 11546 字节。
- .data —— 在 .data 段,大小从前例所示的 800008(hex) 降为只有 000008(hex)。data_array 现在被视为 .bss 段。
- .bss —— 在 .bss 段,大小现在是前例所示的两倍,即 1000008(hex),为两个数组大小之和( bss_array 的 800000(hex) 加上 data_array 的 800000(hex)),但它不会占用执行体中的任何 “空间”。下一个段的偏移量也不会更改。
对段的总结为获得较大数量的内存,大多数应用程序会使用未初始化的数据声明或者使用 malloc 命令。 libhugetlbfs 提供了两种简单的方法来将 .bss 段和由 malloc 命令分配的内存加载进系统大内存页。libhugetlbfs 也提供了将执行体的 .text 段和 .data 段加载进大内存页的方法,但不如 .bss 段和由 malloc 分配的内存那么常见。 |
|
|
|
|
|