| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3108 人关注过本帖, 1 人收藏
标题:程序读取一个5M的文本,居然占用了50+M的内存……请问这是为什么?……
只看楼主 加入收藏
sunb3
Rank: 2
来 自:北京
等 级:论坛游民
威 望:3
帖 子:34
专家分:94
注 册:2017-4-20
结帖率:100%
收藏(1)
已结贴  问题点数:10 回复次数:14 
程序读取一个5M的文本,居然占用了50+M的内存……请问这是为什么?……
如题,
我在练习用单向链表解决读取不确定个数的数据问题。
结构很简单如下所示:

typedef struct Node{
 int num;
 struct Node *next;
}

由于最开始我觉得自己写的append都要在调用时循环指到最后一个节点太不效率了,所以我用了一个“从尾巴开始加起”的这个思路解决增加节点的问题:
图片附件: 游客没有浏览图片的权限,请 登录注册


实现如下:

/*当读取节点的时候,每次都通过node的下一个追加,可以节省无数次遍历所用的时间*/
void file_append(NODE **node,int num) {
    if (!*node) {
        return;
    }
    NODE *temp = create_empty();
    temp->num = num;
    (*node)->next = temp;
    /*这样应该保证每次node都是最后一个节点*/
    (*node) = (*node)->next;
}
 
int file_input(NODE *HEAD,const char *filename) {
    if (!HEAD) {
        return 0;
    }

    NODE *tail = HEAD;
    while (tail->next) {
        tail = tail->next;
    }
    /*这样一来,tail最终指向了最后一个节点*/

    FILE *fp = fopen(filename, "r");
    if (!fp) {
        return 0;
    }
    while (!feof(fp)) {
        int num;
        fscanf(fp, "%d", &num);
        file_append(&tail, num);
    }
    fclose(fp);

    return 1;
}

释放内存的部分就是一个个删除,为了便于读懂我多写了个delete_node:

/*删除指定节点*/
int delete_node(NODE *node) {
    if (!node) {
        return 0;
    }
    memset(node, 0, sizeof(node));
    free(node);
    return 1;
}

/*清空链表所有下级节点*/
int remove_all_nodes(NODE *HEAD) {
    if (!HEAD) {
        return 0;
    }
    NODE *cur = HEAD;
    NODE *temp = NULL;
    while (cur) {
        temp = cur->next;
        cur->next = cur->next->next;
        delete_node(temp);
        cur = cur->next;
    }
    return 1;
}

/*打印指定节点的数据*/
void print_node(NODE *node) {
    printf("%d ",node->num);
}


/*打印整个链表的数据*/
void print_chaintab(NODE *HEAD) {
    NODE *temp = HEAD->next;
    while (temp) {
        print_node(temp);
        temp = temp->next;
    }
    printf("\n");
}


其它部分就都不相关了,也就没有详细列出来。
 
 
int main(int argc,char *argv[]) {

    if (argc < 2) {
        printf("请指明文件名\n");
        getchar();
        return 1;
    }

    printf("开始读取文件……");
    getchar();

    NODE *head = create_empty();

    clock_t start, end;

    start = clock();
    if(!file_input(head, argv[1])){
        printf("文件不存在!\n");
        getchar();
        return 2;
    }
    end = clock();

    printf("文件加载完毕!共耗时%d毫秒。\n",end - start);
    /*print_chaintab(head);*/

    getchar();

    remove_all_nodes(head);
    free(head);

    printf("记录清除完毕……");
    getchar();

    return 0;
}


之后我自己生成了一个放满随机数(大约100万个)的文本文件,大小为5.39M。
在代码中可以看到:我分别在main的读取前,读取后和内存清理前设置了getchar()来观察内存变化。

于是问题来了:
读取文件前,程序只占用了572K的内存
图片附件: 游客没有浏览图片的权限,请 登录注册


读取完所有记录居然有将近54M的占用
图片附件: 游客没有浏览图片的权限,请 登录注册


而释放后内存占用居然还没变……
图片附件: 游客没有浏览图片的权限,请 登录注册


请问:
1、为什么内存占用了50多M?这已经相当于是文件大小的10倍多了
2、到底我的清除链表有没有完成任务?这些内存是否已经被清除掉了?
3、为什么清除后的程序没有恢复到500多K?如何让它恢复成初始大小?


新来的用户,应该没有多少分,所以先来10分。希望各位前辈指点迷津,谢谢!
搜索更多相关主题的帖子: return 
2017-04-20 10:56
renkejun1942
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:不是这样
等 级:贵宾
威 望:33
帖 子:1645
专家分:5297
注 册:2016-12-1
收藏
得分:1 
typedef struct Node{
 int num;
 struct Node *next;
}

你的这个东西就占用了8个字节。
你释放了内存,但是任务管理器上的显示却没有减少,那是因为系统了为偷懒。

09:30 05/21 种下琵琶种子,能种活么?等待中……
21:50 05/27 没有发芽。
20:51 05/28 没有发芽。
23:03 05/29 没有发芽。
23:30 06/09 我有预感,要发芽了。
2017-04-20 11:03
sunb3
Rank: 2
来 自:北京
等 级:论坛游民
威 望:3
帖 子:34
专家分:94
注 册:2017-4-20
收藏
得分:0 
以下是引用renkejun1942在2017-4-20 11:03:50的发言:

typedef struct Node{
 int num;
 struct Node *next;
}

你的这个东西就占用了8个字节。
你释放了内存,但是任务管理器上的显示却没有减少,那是因为系统了为偷懒。



额……8字节的话……一共100万个数据,也就是800万字节(Byte),除以1024是7812.5KB,那也应该只有7M多大小啊=_=……

====================================================================================================================
不是重点……重点是……如果我有8G的文件要读取,那岂不是至少要80G内存才能读取进来?
那该如何解决大内存占用呢?
毕竟还要对文件中的数进行排序,查找然后输出出去……

[此贴子已经被作者于2017-4-20 11:09编辑过]


除了基础……我什么都不会……
2017-04-20 11:07
renkejun1942
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:不是这样
等 级:贵宾
威 望:33
帖 子:1645
专家分:5297
注 册:2016-12-1
收藏
得分:0 
回复 3楼 sunb3
字符串排序是不会用链表的,链表占用太大。
大文件排序,请自行查阅 外部排序。

09:30 05/21 种下琵琶种子,能种活么?等待中……
21:50 05/27 没有发芽。
20:51 05/28 没有发芽。
23:03 05/29 没有发芽。
23:30 06/09 我有预感,要发芽了。
2017-04-20 11:14
forever74
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:CC
等 级:版主
威 望:58
帖 子:1685
专家分:4252
注 册:2007-12-27
收藏
得分:1 
每个malloc系的函数调用都是有代价的,根据实现的不同,代价也不同,但绝不仅仅是申请8字节就占用8字节。
一般来说每次malloc的绝对代价都是相同的,因此减少malloc的次数可以有效减少相对代价。
所以成熟的软件应该每次malloc放进去100或者1000个数据而不是一个,用完以后再次malloc。你可以试一下,这样就你的数据占用的内存会远远小于现在的数量。

后加的内容:我说的代价是指对内存的多吃多占。

[此贴子已经被作者于2017-4-20 11:32编辑过]


对宇宙最严谨的描述应该就是宇宙其实是不严谨的
2017-04-20 11:27
sunb3
Rank: 2
来 自:北京
等 级:论坛游民
威 望:3
帖 子:34
专家分:94
注 册:2017-4-20
收藏
得分:0 
以下是引用renkejun1942在2017-4-20 11:14:50的发言:

字符串排序是不会用链表的,链表占用太大。
大文件排序,请自行查阅 外部排序。



不是字符串排序,是读取文本中的数字,以int排序的

除了基础……我什么都不会……
2017-04-20 11:31
sunb3
Rank: 2
来 自:北京
等 级:论坛游民
威 望:3
帖 子:34
专家分:94
注 册:2017-4-20
收藏
得分:0 
以下是引用forever74在2017-4-20 11:27:25的发言:

每个malloc系的函数调用都是有代价的,根据实现的不同,代价也不同,但绝不仅仅是申请8字节就占用8字节。
一般来说每次malloc的绝对代价都是相同的,因此减少malloc的次数可以有效减少相对代价。
所以成熟的软件应该每次malloc放进去100或者1000个数据而不是一个,用完以后再次malloc。你可以试一下,这样就你的数据占用的内存会远远小于现在的数量。



您的意思是说我mallocN多个然后再分别调用么?
比如我有10000个数据,那我最好每次申请10000个malloc?但是申请过来后我如何使用之后的这些内存呢?
比如……

NODE *head = calloc(10000,sizeof(NODE));
head得到了,我如何得到后面的操作?…………head ++?再指定一个p_head记录头地址?

除了基础……我什么都不会……
2017-04-20 11:53
forever74
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:CC
等 级:版主
威 望:58
帖 子:1685
专家分:4252
注 册:2007-12-27
收藏
得分:1 
鱼和熊掌不可兼得,想省内存就得忍受代码复杂化呀同志。

对宇宙最严谨的描述应该就是宇宙其实是不严谨的
2017-04-20 12:04
sunb3
Rank: 2
来 自:北京
等 级:论坛游民
威 望:3
帖 子:34
专家分:94
注 册:2017-4-20
收藏
得分:0 
以下是引用forever74在2017-4-20 12:04:09的发言:

鱼和熊掌不可兼得,想省内存就得忍受代码复杂化呀同志。


恩,这个道理我明白,我只是不知道该怎么写……您看能否给我指点指点我应该巩固什么方面(内存管理?)的能力?我有点理不清头绪=_=|||

另外,我想顺便了解一下比如大数据这样的玩意,一分钟10几G上下的数据,C语言如何处理这些数据还不会占用那么多内存?……

[此贴子已经被作者于2017-4-20 13:08编辑过]


除了基础……我什么都不会……
2017-04-20 13:07
初学编程的人
Rank: 2
等 级:论坛游民
威 望:2
帖 子:90
专家分:84
注 册:2017-3-12
收藏
得分:1 
学习汇编吧,看看这些函数调用的时候计算机到底需要做哪些工作,学完了应该就明白了。我也是刚开始学,不想学精通只是为了对计算机有个了解。
2017-04-20 15:32
快速回复:程序读取一个5M的文本,居然占用了50+M的内存……请问这是为什么?…… ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017450 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved