代码运行效率及程序大小分析一例
2013-10-24 22:01
246 查看
之前一直看到有经验的程序员说,代码写得太低劣了,许多变量都定义成全局的,当时的理解大致是这样程序的健壮性不好,不利于移植、修改和维护,牵一发而动全身。今天在测试一个代码运行效率的程序时,做了一个测试程序,让我对这个问题有了新的认识。这个程序要说明的问题是,尽可能在循环的时候只运行本层的数据,单层的循环有利于节省CPU的运行时间。
测试代码如下:
#include<stdio.h>
#include<windows.h>
int data1[10000000] = {0,1};
int data2[10000000] = {0,1};
void loop_layer_test();
int main()
{
loop_layer_test();
return 0;
}
void loop_layer_test()
{
int m = GetTickCount();
int outer = 0;
int inner = 0;
for(outer = 0; outer < 10000000; outer ++)
{
data1[outer] = outer;
data2[outer] = outer;
}
printf("%d\n", GetTickCount() - m);
m = GetTickCount();;
for(inner = 0; inner < 10000000; inner ++)
{
data1[inner] = inner;
}
for(outer = 0; outer < 10000000; outer ++)
{
data2[outer] = outer;
}
printf("%d\n", GetTickCount() - m);
}
程序运行的结果为:94,62
这说明在循环中要进行相关的遍历、赋值操作,如果不是必须的话,最好可以做到只运行单层数据,如果数据量特别大的话,会节约大量CPU的时间。
到这里本来对这段代码的分析已经结束了,可是无意中,我将鼠标放到了这个程序所在的文件夹,171M,这个程序所在的文件夹竟然171M !这让我感到很震惊!我再看看生成exe文件,92M !不到100行的代码,没有嵌入任何资源,生成的程序达到了92M,这是让人不能忍受的。
作为一个菜鸟,面对这样的问题,总是无法理解的。我再去认真分析这个程序,数据,还是这个数据太多了,让程序体积如此庞大。问题出现在
int data1[10000000] = {0,1};
int data2[10000000] = {0,1};
这两条语句,这样定义了2个数组并进行了初始化,消耗了大量的内存,在全局变量区生成了大量的数据,导致程序体积如此庞大。要解决这个问题,我想到的方法是将数据放到loop_layer_test函数中,这样在调用完loop_layer_tes函数后,会释放掉这些生成的大量数据,程序的体积自然也就下来了。
按照这样的思路,我将
int data1[10000000] = {0,1};
int data2[10000000] = {0,1};
放入了loop_layer_test函数中,编译时没有问题,运行时发生如下错误:
我忽略了一个基本事实,栈中数据量是不能超过2M的,这么多的数据放入函数中,会导致栈溢出。
既然在栈中不能储存这90多M的数据,那就开辟一块堆内存吧,在堆中对数据大小原则上是没有限制的。于是,将以上数组的定义和赋值改为动态分配:
int *data1 = (int*)malloc(sizeof(int[10000000]));
int *data2 = (int*)malloc(sizeof(int[10000000]));
程序的其他部分不需要作任何修改,只需在结尾加上:
free(data1);
free(data2);
语句,释放掉申请的内存。至此,对程序的改造算是完成了。编译运行都没有问题,再去看看生成了exe文件,只有168k。这才是一个正常的程序。
后来我在看之前写的那个全局变量的代码,发现在全局变量区只是声明而不不为数组分配内存,也就是将代码改成如下形式:
int data1[10000000] ;
int data2[10000000] ;
也是可以大大缩小程序体积的,这样程序也只有100多k。
通过这个demo,总结以下几点:
(1)尽可能在循环的时候只运行本层的数据,单层的循环有利于节省CPU的运行时间;
(2)如果不是必须的话,尽可能少使用全局变量。如果要定义全局变量,也最好不要分配内存;
(3)程序的大小是在main函数return那一刻敲定的,return时内存中有多少数据将直接决定程序的大小;
(4)栈中不能放大量数据,会产生栈溢出异常。
PS:第一次写技术类文章,叙述难免含糊。本人菜鸟一个,如理解有误,欢迎指正!
测试代码如下:
#include<stdio.h>
#include<windows.h>
int data1[10000000] = {0,1};
int data2[10000000] = {0,1};
void loop_layer_test();
int main()
{
loop_layer_test();
return 0;
}
void loop_layer_test()
{
int m = GetTickCount();
int outer = 0;
int inner = 0;
for(outer = 0; outer < 10000000; outer ++)
{
data1[outer] = outer;
data2[outer] = outer;
}
printf("%d\n", GetTickCount() - m);
m = GetTickCount();;
for(inner = 0; inner < 10000000; inner ++)
{
data1[inner] = inner;
}
for(outer = 0; outer < 10000000; outer ++)
{
data2[outer] = outer;
}
printf("%d\n", GetTickCount() - m);
}
程序运行的结果为:94,62
这说明在循环中要进行相关的遍历、赋值操作,如果不是必须的话,最好可以做到只运行单层数据,如果数据量特别大的话,会节约大量CPU的时间。
到这里本来对这段代码的分析已经结束了,可是无意中,我将鼠标放到了这个程序所在的文件夹,171M,这个程序所在的文件夹竟然171M !这让我感到很震惊!我再看看生成exe文件,92M !不到100行的代码,没有嵌入任何资源,生成的程序达到了92M,这是让人不能忍受的。
作为一个菜鸟,面对这样的问题,总是无法理解的。我再去认真分析这个程序,数据,还是这个数据太多了,让程序体积如此庞大。问题出现在
int data1[10000000] = {0,1};
int data2[10000000] = {0,1};
这两条语句,这样定义了2个数组并进行了初始化,消耗了大量的内存,在全局变量区生成了大量的数据,导致程序体积如此庞大。要解决这个问题,我想到的方法是将数据放到loop_layer_test函数中,这样在调用完loop_layer_tes函数后,会释放掉这些生成的大量数据,程序的体积自然也就下来了。
按照这样的思路,我将
int data1[10000000] = {0,1};
int data2[10000000] = {0,1};
放入了loop_layer_test函数中,编译时没有问题,运行时发生如下错误:
我忽略了一个基本事实,栈中数据量是不能超过2M的,这么多的数据放入函数中,会导致栈溢出。
既然在栈中不能储存这90多M的数据,那就开辟一块堆内存吧,在堆中对数据大小原则上是没有限制的。于是,将以上数组的定义和赋值改为动态分配:
int *data1 = (int*)malloc(sizeof(int[10000000]));
int *data2 = (int*)malloc(sizeof(int[10000000]));
程序的其他部分不需要作任何修改,只需在结尾加上:
free(data1);
free(data2);
语句,释放掉申请的内存。至此,对程序的改造算是完成了。编译运行都没有问题,再去看看生成了exe文件,只有168k。这才是一个正常的程序。
后来我在看之前写的那个全局变量的代码,发现在全局变量区只是声明而不不为数组分配内存,也就是将代码改成如下形式:
int data1[10000000] ;
int data2[10000000] ;
也是可以大大缩小程序体积的,这样程序也只有100多k。
通过这个demo,总结以下几点:
(1)尽可能在循环的时候只运行本层的数据,单层的循环有利于节省CPU的运行时间;
(2)如果不是必须的话,尽可能少使用全局变量。如果要定义全局变量,也最好不要分配内存;
(3)程序的大小是在main函数return那一刻敲定的,return时内存中有多少数据将直接决定程序的大小;
(4)栈中不能放大量数据,会产生栈溢出异常。
PS:第一次写技术类文章,叙述难免含糊。本人菜鸟一个,如理解有误,欢迎指正!
相关文章推荐
- Myeclipse最全快捷键
- Python 专题五 XML JSON解析
- C++中的空类,默认产生哪些类成员函数?
- 【JAVA】this和super关键字的用法
- c/c++连接mysql数据库
- 非C++内建型别A和B, 在哪几种情况下B能隐式转化为A?
- 【C++第八课】---操作符重载上
- struts2实现文件上传和下载
- Java静态类
- 转:myeclipse 8.x 插件安装方法终极总结
- JVM性能优化, Part 3 - 垃圾回收
- myeclipse的快捷键和myeclipse快捷键设置
- 关于java web自动化测试工具 selenium
- eclipse 下一些常用到插件到官方地址
- Monetdb源代码——mal_client.h
- Java基础知识<2>
- noip历届 && 打代码常犯错误总结
- Java Properties无需重启服务器即可动态读取最新键值
- java访问修饰符
- ffdshow 源代码分析 2: 位图覆盖滤镜(对话框部分Dialog)