前段时间写了一个测试程序,每次都在第430个测试用例左右就会出现异常,然后程序终止。一开始还以为是使用的内存没有释放导致系统内存占用过多而出现问题。在一通调试(比如老老实实写一下释放内存的代码)之后,发现还是没有什么作用。最后干脆把测试的核心功能代码(也就是我要测试的真正功能代码)删掉,只保留了用于控制测试的代码,最后发现我把打开文件的代码关掉之后,就没有出现问题了。一看,惊了,每次打开的文件没有关闭操作。

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <stdlib.h>

int main() {
for (int i = 0; i < 20000; ++i) {
printf("%d\n", i);
FILE *f = fopen("/data/in.txt", "w");
fprintf(f, "%d\n", i);
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
0
1
2
...
...
...
4858
4859
4860
4861
[1] 24575 segmentation fault cmake-build-debug/open_file_limits_test

而加上 fclose(f); 问题就解决了。

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>

int main() {
for (int i = 0; i < 20000; ++i) {
printf("%d\n", i);
FILE *f = fopen("/data/in.txt", "w");
fprintf(f, "%d\n", i);
fclose(f);
}
return 0;
}

当然,事情到这里并没有结束,为什么之前我测试的时候是430左右,这里却是4861呢?因为这里是打开了文件,而之前写的是打开进程管道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
for (int i = 0; i < 20000; ++i) {
char *cmd = (char *) malloc(sizeof(char) * 65535);
memset(cmd, 0, sizeof(char) * 65535);
sprintf(cmd, "python3 -c \"print(1 == 1)\"");
FILE *f = popen(cmd, "r+");
char *res = (char *) malloc(sizeof(char) * 1024);
memset(res, 0, sizeof(char) * 1024);
fscanf(f, "%s", res);
printf("%d => %s\n", i, res);
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
0 => True
1 => True
2 => True
...
...
...
525 => True
526 => True
527 => True
528 => True
529 => True
530 => True
531 => True
[1] 38030 segmentation fault cmake-build-debug/open_file_limits_test

而且这里如果要关闭这个文件不能使用 fclose(f)' 不然在运行第二个开始都读取不了数据。

1
2
3
4
5
6
7
> cmake-build-debug/open_file_limits_test
0 => True
1 =>
2 =>
3 =>
4 =>
5 =>

这里应该使用 pclose(f); ,当然动态分配的内存需要释放掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
for (int i = 0; i < 20000; ++i) {
char *cmd = (char *) malloc(sizeof(char) * 65535);
memset(cmd, 0, sizeof(char) * 65535);
sprintf(cmd, "python3 -c \"print(1 == 1)\"");
FILE *f = popen(cmd, "r+");
char *res = (char *) malloc(sizeof(char) * 1024);
memset(res, 0, sizeof(char) * 1024);
fscanf(f, "%s", res);
printf("%d => %s\n", i, res);
pclose(f);
free(cmd);
free(res);
}
return 0;
}