fadvise64系统调用及示例

fadvise64 - 文件访问建议

函数介绍

fadvise64是一个Linux系统调用,用于向内核提供关于文件访问模式的建议。它帮助内核优化文件I/O操作,提高性能。fadvise64系统调用详解,提供文件访问建议函数示例与使用方法,优化Linux性能必备。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

关键词:fadvise64 系统调用, fadvise64 函数用法, linux fadvise64 详解, fadvise64 示例代码, linux 系统调用 fadvise64, fadvise64 文件访问建议, 如何使用 fadvise64, fadvise64 系统调用介绍, linux fadvise64 函数说明, fadvise64 作用与用法

函数原型

1
2
3
4
5
6
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>

int fadvise64(int fd, off_t offset, off_t len, int advice);

功能

向内核提供文件访问模式建议,帮助内核优化缓存和预读策略。

参数

  • int fd: 文件描述符

  • off_t offset: 建议适用的文件起始偏移量

  • off_t len: 建议适用的文件长度(0表示到文件末尾)

int advice: 访问建议类型

  • POSIX_FADV_NORMAL: 普通访问模式(默认)

  • POSIX_FADV_SEQUENTIAL: 顺序访问

  • POSIX_FADV_RANDOM: 随机访问

  • POSIX_FADV_NOREUSE: 数据只访问一次

  • POSIX_FADV_WILLNEED: 数据即将被访问

  • POSIX_FADV_DONTNEED: 数据不再需要

返回值

  • 成功时返回0

  • 失败时返回-1,并设置errno

特殊限制

  • 需要Linux 2.5.60以上内核支持

  • 某些文件系统可能不完全支持

  • 建议只是提示,内核可能忽略

相似函数

  • madvise(): 内存访问建议

  • readahead(): 文件预读

  • posix_fadvise(): POSIX标准版本

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <sys/syscall.h>

// 系统调用包装
static int fadvise64_wrapper(int fd, off_t offset, off_t len, int advice) {
return syscall(__NR_fadvise64, fd, offset, len, advice);
}

// 创建测试文件
int create_test_file(const char* filename, size_t size) {
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建测试文件失败");
return -1;
}

// 写入测试数据
char* buffer = malloc(4096);
if (buffer) {
memset(buffer, 'A', 4096);
for (size_t i = 0; i < size; i += 4096) {
size_t write_size = (size - i > 4096) ? 4096 : (size - i);
write(fd, buffer, write_size);
}
free(buffer);
}

return fd;
}

int main() {
int fd;
int result;

printf("=== Fadvise64 函数示例 ===\n");

// 示例1: 基本使用
printf("\n示例1: 基本使用\n");

// 创建大文件用于测试
fd = create_test_file("test_fadvise64.dat", 1024 * 1024); // 1MB
if (fd == -1) {
exit(EXIT_FAILURE);
}
printf("创建测试文件: test_fadvise64.dat (1MB)\n");

close(fd);

// 重新打开文件进行测试
fd = open("test_fadvise64.dat", O_RDONLY);
if (fd == -1) {
perror("打开测试文件失败");
unlink("test_fadvise64.dat");
exit(EXIT_FAILURE);
}
printf("打开测试文件进行fadvise64测试\n");

// 示例2: 不同的访问建议
printf("\n示例2: 不同的访问建议\n");

// POSIX_FADV_NORMAL - 普通访问模式
result = fadvise64_wrapper(fd, 0, 0, POSIX_FADV_NORMAL);
if (result == 0) {
printf("设置POSIX_FADV_NORMAL成功\n");
} else {
printf("设置POSIX_FADV_NORMAL失败: %s\n", strerror(errno));
}

// POSIX_FADV_SEQUENTIAL - 顺序访问
result = fadvise64_wrapper(fd, 0, 1024*1024, POSIX_FADV_SEQUENTIAL);
if (result == 0) {
printf("设置POSIX_FADV_SEQUENTIAL成功\n");
printf("提示内核将进行顺序访问,优化预读策略\n");
}

// POSIX_FADV_RANDOM - 随机访问
result = fadvise64_wrapper(fd, 0, 1024*1024, POSIX_FADV_RANDOM);
if (result == 0) {
printf("设置POSIX_FADV_RANDOM成功\n");
printf("提示内核将进行随机访问,减少预读\n");
}

// POSIX_FADV_WILLNEED - 数据即将被访问
result = fadvise64_wrapper(fd, 0, 64*1024, POSIX_FADV_WILLNEED);
if (result == 0) {
printf("设置POSIX_FADV_WILLNEED成功\n");
printf("提示内核预读前64KB数据\n");
}

// POSIX_FADV_DONTNEED - 数据不再需要
result = fadvise64_wrapper(fd, 0, 64*1024, POSIX_FADV_DONTNEED);
if (result == 0) {
printf("设置POSIX_FADV_DONTNEED成功\n");
printf("提示内核可以丢弃前64KB数据的缓存\n");
}

// POSIX_FADV_NOREUSE - 数据只访问一次
result = fadvise64_wrapper(fd, 64*1024, 64*1024, POSIX_FADV_NOREUSE);
if (result == 0) {
printf("设置POSIX_FADV_NOREUSE成功\n");
printf("提示内核64KB-128KB范围的数据只访问一次\n");
}

// 示例3: 错误处理演示
printf("\n示例3: 错误处理演示\n");

// 使用无效的文件描述符
result = fadvise64_wrapper(999, 0, 1024, POSIX_FADV_NORMAL);
if (result == -1) {
if (errno == EBADF) {
printf("无效文件描述符错误处理正确: %s\n", strerror(errno));
}
}

// 使用无效的建议类型
result = fadvise64_wrapper(fd, 0, 1024, 999);
if (result == -1) {
if (errno == EINVAL) {
printf("无效建议类型错误处理正确: %s\n", strerror(errno));
}
}

// 使用负的偏移量
result = fadvise64_wrapper(fd, -1024, 1024, POSIX_FADV_NORMAL);
if (result == -1) {
printf("负偏移量处理: %s\n", strerror(errno));
}

// 示例4: 实际使用场景演示
printf("\n示例4: 实际使用场景演示\n");

// 场景1: 大文件顺序读取
printf("场景1: 大文件顺序读取优化\n");
printf("处理大日志文件的代码示例:\n");
printf("int process_large_log(const char* filename) {\n");
printf(" int fd = open(filename, O_RDONLY);\n");
printf(" if (fd == -1) return -1;\n");
printf(" \n");
printf(" // 提示内核将顺序访问整个文件\n");
printf(" posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);\n");
printf(" \n");
printf(" // 读取处理文件...\n");
printf(" char buffer&#91;8192];\n");
printf(" ssize_t bytes;\n");
printf(" while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) {\n");
printf(" // 处理数据\n");
printf(" }\n");
printf(" \n");
printf(" close(fd);\n");
printf(" return 0;\n");
printf("}\n\n");

// 场景2: 随机访问数据库文件
printf("场景2: 随机访问数据库文件\n");
printf("数据库文件访问优化:\n");
printf("int access_database_file(const char* filename) {\n");
printf(" int fd = open(filename, O_RDWR);\n");
printf(" if (fd == -1) return -1;\n");
printf(" \n");
printf(" // 提示内核将随机访问文件\n");
printf(" posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);\n");
printf(" \n");
printf(" // 根据需要预读特定区域\n");
printf(" posix_fadvise(fd, index_offset, index_size, POSIX_FADV_WILLNEED);\n");
printf(" \n");
printf(" // 访问完成后释放不需要的缓存\n");
printf(" posix_fadvise(fd, old_data_offset, old_data_size, POSIX_FADV_DONTNEED);\n");
printf(" \n");
printf(" close(fd);\n");
printf(" return 0;\n");
printf("}\n\n");

// 示例5: 不同建议类型的效果说明
printf("示例5: 不同建议类型的效果说明\n");

printf("POSIX_FADV_NORMAL:\n");
printf(" - 默认访问模式\n");
printf(" - 使用系统默认的预读和缓存策略\n");
printf(" - 适用于一般情况\n\n");

printf("POSIX_FADV_SEQUENTIAL:\n");
printf(" - 优化顺序访问\n");
printf(" - 增加预读量\n");
printf(" - 适用于大文件顺序读取\n");
printf(" - 提高顺序读取性能\n\n");

printf("POSIX_FADV_RANDOM:\n");
printf(" - 优化随机访问\n");
printf(" - 减少或禁用预读\n");
printf(" - 适用于数据库、索引文件\n");
printf(" - 减少不必要的内存占用\n\n");

printf("POSIX_FADV_NOREUSE:\n");
printf(" - 数据只访问一次\n");
printf(" - 访问后尽快释放缓存\n");
printf(" - 适用于一次性处理的大文件\n");
printf(" - 节省内存资源\n\n");

printf("POSIX_FADV_WILLNEED:\n");
printf(" - 数据即将被访问\n");
printf(" - 提前预读数据到缓存\n");
printf(" - 适用于已知访问模式的场景\n");
printf(" - 减少实际访问时的等待\n\n");

printf("POSIX_FADV_DONTNEED:\n");
printf(" - 数据不再需要\n");
printf(" - 尽快释放缓存空间\n");
printf(" - 适用于处理完成的数据\n");
printf(" - 释放系统资源\n\n");

// 示例6: 性能测试演示
printf("示例6: 性能影响演示\n");

printf("fadvise64对性能的影响:\n");
printf("1. 正确使用可显著提高I/O性能\n");
printf("2. 错误使用可能导致性能下降\n");
printf("3. 效果因文件系统和硬件而异\n");
printf("4. 大文件效果更明显\n");
printf("5. 需要根据实际访问模式选择\n\n");

// 示例7: 实际应用建议
printf("示例7: 实际应用建议\n");

printf("使用fadvise64的最佳实践:\n");
printf("1. 在文件打开后尽早设置建议\n");
printf("2. 根据实际访问模式选择合适的建议\n");
printf("3. 对于大文件效果更明显\n");
printf("4. 不要过度使用,避免增加系统负担\n");
printf("5. 在长时间运行的应用中适时调整\n");
printf("6. 测试不同建议对性能的影响\n\n");

printf("常见应用场景:\n");
printf("- 大文件处理和分析\n");
printf("- 数据库系统\n");
printf("- 日志处理系统\n");
printf("- 备份和归档工具\n");
printf("- 媒体播放器\n");
printf("- 科学计算应用\n\n");

// 示例8: 与相关函数的对比
printf("示例8: 与相关函数的对比\n");

printf("fadvise64 vs madvise:\n");
printf("fadvise64:\n");
printf(" - 针对文件I/O\n");
printf(" - 影响文件缓存策略\n");
printf(" - 在文件描述符上操作\n\n");

printf("madvise:\n");
printf(" - 针对内存映射\n");
printf(" - 影响内存管理策略\n");
printf(" - 在内存地址上操作\n\n");

printf("fadvise64 vs readahead:\n");
printf("fadvise64:\n");
printf(" - 更通用的建议机制\n");
printf(" - 支持多种访问模式\n");
printf(" - 可以指定文件区域\n\n");

printf("readahead:\n");
printf(" - 专门用于预读\n");
printf(" - 立即执行预读操作\n");
printf(" - 较为直接但不够灵活\n\n");

// 清理资源
close(fd);
unlink("test_fadvise64.dat");

printf("总结:\n");
printf("fadvise64是Linux提供的文件访问优化机制\n");
printf("通过向内核提供访问建议来优化性能\n");
printf("支持多种访问模式的优化\n");
printf("是处理大文件和特定访问模式的重要工具\n");
printf("需要根据实际应用场景合理使用\n");

return 0;
}

https://www.calcguide.tech/2025/08/11/fadvise64系统调用及示例-3/

data-ad-format="auto" data-full-width-responsive="true">