1. 修改/etc/profile文件
如果你的计算机仅仅作为开发使用时推荐使用这种方法,因为所有用户的shell都有权使用这些环境变量,可能会给系统带来安全性问题。
·用文本编辑器打开/etc/profile
·在profile文件末尾加入:
[java]
JAVA_HOME=/usr/share/jdk1.5.0_05
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME
export PATH
export CLASSPATH
[/java]
·重新登录
·注解
a. 你要将 /usr/share/jdk1.5.0_05jdk 改为你的jdk安装目录
b. linux下用冒号“:”来分隔路径
c. $PATH / $CLASSPATH / $JAVA_HOME 是用来引用原来的环境变量的值
在设置环境变量时特别要注意不能把原来的值给覆盖掉了,这是一种
常见的错误。
d. CLASSPATH中当前目录“.”不能丢,把当前目录丢掉也是常见的错误。
e. export是把这三个变量导出为全局变量。
f. 大小写必须严格区分。
2. 修改.bashrc文件
这种方法更为安全,它可以把使用这些环境变量的权限控制到用户级别,如果你需要给某个用户权限使用这些环境变量,你只需要修改其个人用户主目录下的.bashrc文件就可以了。
·用文本编辑器打开用户目录下的.bashrc文件
·在.bashrc文件末尾加入:
set JAVA_HOME=/usr/share/jdk1.5.0_05
export JAVA_HOME
set PATH=$JAVA_HOME/bin:$PATH
export PATH
set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH
·重新登录
3. 直接在shell下设置变量
不赞成使用这种方法,因为换个shell,你的设置就无效了,因此这种方法仅仅是临时使用,以后要使用的时候又要重新设置,比较麻烦。
只需在shell终端执行下列命令:
export JAVA_HOME=/usr/share/jdk1.5.0_05
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
1. 手动安装jdk5
首先,在http://java.sun.com下载jdk-5u1-linux- i586.bin,据说这个操作起来比较简单,不需要转换。
然后,可以把它放置在任何你喜欢的文件夹,如果是像我样的菜鸟(学习linux不到一个星期的),建议把它放置到主文件夹(/home/*)下。
下面开始安装jdk:
在网上查的一些资料上都是把jdk安装在/usr /lib/jvm/jdk下面,也有安装在/opt下的,我在这里介绍的就是把它安装在了/opt下,
终端下进入你存放jdk-5u1- linux-i586.bin,例如我的位置是:/home/my
$ sudo -s ./jdk-5u1-linux-i586.bin /opt
一路回车,直到询问是否安装,输入yes回车
ok,安装完毕,下面配置环境变量
配置 classpath,修改所有用户的环境变量
$ sudo gedit /etc/profile
在文件最后添加
#set java environment
JAVA_HOME=/opt/jdk1.5.0_10
export JRE_HOME=/opt/jdk1.5.0_10/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
[注意]
以上文件不要写错,一旦写错,重启后很可能进不了系统!!!不要害怕,继续看吧!
具体情况如下:登录输入密码以后弹出对话框(您的会话不到10秒就结束…请以安全模式登录,查看是否可以解决)点击左下角“选项”进入安全模式,把上面的信息改好就可以了(本人亲身经历,555)
重新启动计算机,用命令测试jdk的版本
java -version
显示如下信息:成功安装
java version “1.5.0_10″
Java(TM) SE Runtime Environment (build 1.5.0_10)
Java HotSpot(TM) Client VM (build 1.5.0_10, mixed mode, sharing)
Ubuntu默认的编码标准是UTF-8,而很多应用都是在windows下开发的,默认编码是gb2312,这样移植过去就会产生乱码。
改为GBK编码:
$ sudo locale-gen
编辑 /var/lib/locales/supported.d/local
添加 zh_CN.GBK GBK
编辑 /etc/environment
修改为
LANG=zh_CN.GBK
LANGUAGE=”zh_CN:zh:en_US:en”
GST_ID3_TAG_RNCODING=GBK
LC_CTYLE=zh_CN.GBK
LC_ALL=”zh_CN.GBK”
重启reboot。
近日发现写的一个java程序的数据库连接在大压力下工作不打正常,因此研究了一下dbcp,中间为了查看mysql服务器的数据库连接情况,需要使用 netstat来查看端口和连接, 将使用到的命令整理了一下备忘, 这些命令同样可以用于查看其他运用程序的端口和连接情况.
netstat 命令是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息,这里我只用到其中的部分功能.
直接输入netstat,显示
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:41144 localhost:41147 ESTABLISHED
tcp 0 0 localhost:21576 localhost:21579 ESTABLISHED
tcp 0 0 linux.local:telnet 10.3.18.129:nbx-au ESTABLISHED
tcp 1 0 localhost:39706 localhost:58099 CLOSE_WAIT
……
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ] DGRAM 910 /var/named/dev/log
unix 2 [ ] DGRAM 908 /var/lib/dhcp/dev/log
unix 8 [ ] DGRAM 906 /dev/log
…..
输出结果可以分为两个部分,一个是Active Internet connections,另一个是Active UNIX domain sockets.
netstat 的常用参数: – t、- u、- w和- x分别表示TCP、UDP、RAW和UNIX套接字连接。-a标记,还会显示出等待连接(也就是说处于监听模式)的套接字。-l 显示正在被监听(listen)的端口, -n表示直接显示端口数字而不是通过察看/etc/service来转换为端口名,-p选项表示列出监听的程序
1) netstat -tl
查看当前tcp监听端口
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:rrac *:* LISTEN
tcp 0 0 *:34006 *:* LISTEN
……
2) netstat -tlp
查看当前tcp监听端口, 需要显示监听的程序名,当不清楚mysql的监听端口时比较好用
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 *:rrac *:* LISTEN -
tcp 0 0 *:34006 *:* LISTEN 23425/mysqld
……
3) netstat -tl | grep 34006
只查看mysql的监听端口,当前启动的mysql端口为34006,明确知道mysql监听端口时使用
4) netstat -ta | grep 34006
tcp 0 0 *:34006 *:* LISTEN
tcp 0 0 linux.local:34006 linux.local:41485 ESTABLISHED
tcp 0 0 linux.local:34006 linux.local:41486 ESTABLISHED
…
tcp 0 0 10.3.2.35:41488 10.3.2.35:34006 ESTABLISHED
tcp 0 0 10.3.2.35:41489 10.3.2.35:34006 ESTABLISHED
tcp 0 0 10.3.2.35:41490 10.3.2.35:34006 ESTABLISHED
由于数据库和运用程序都放在同一台机器了,因此这里连接被显示了两次. 可以使用-p参数来显示PID,然后grep PID.
5) netstat -tap | grep 34006 | grep 23425
23425是当前mysql的PID
tcp 0 0 *:34006 *:* LISTEN 23425/mysqld
tcp 0 0 linux.local:34006 linux.local:41510 ESTABLISHED 23425/mysqld
tcp 0 0 linux.local:34006 linux.local:41511 ESTABLISHED 23425/mysqld
tcp 0 0 linux.local:34006 linux.local:41516 ESTABLISHED 23425/mysqld
/etc/network/interfaces
打开后里面可设置DHCP或手动设置静态ip。前面auto eth0,让网卡开机自动挂载.
1. 以DHCP方式配置网卡
编辑文件/etc/network/interfaces:
sudo vi /etc/network/interfaces
并用下面的行来替换有关eth0的行:
# The primary network interface - use DHCP to find our address
auto eth0
iface eth0 inet dhcp
用下面的命令使网络设置生效:
sudo /etc/init.d/networking restart
也可以在命令行下直接输入下面的命令来获取地址
sudo dhclient eth0
2. 为网卡配置静态IP地址
编辑文件/etc/network/interfaces:
sudo vi /etc/network/interfaces
并用下面的行来替换有关eth0的行:# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.3.90
gateway 192.168.3.1
netmask 255.255.255.0
#network 192.168.3.0
#broadcast 192.168.3.255
将上面的ip地址等信息换成你自己就可以了.用下面的命令使网络设置生效:
sudo /etc/init.d/networking restart
3. 设定第二个IP地址(虚拟IP地址)
编辑文件/etc/network/interfaces:
sudo vi /etc/network/interfaces
在该文件中添加如下的行:
auto eth0:1
iface eth0:1 inet static
address 192.168.1.60
netmask 255.255.255.0
network x.x.x.x
broadcast x.x.x.x
gateway x.x.x.x
根据你的情况填上所有诸如address,netmask,network,broadcast和gateways等信息.
用下面的命令使网络设置生效:
sudo /etc/init.d/networking restart
4. 设置主机名称(hostname)
使用下面的命令来查看当前主机的主机名称:
sudo /bin/hostname
使用下面的命令来设置当前主机的主机名称:
sudo /bin/hostname newname
系统启动时,它会从/etc/hostname来读取主机的名称.
关于设置主机名称的更多信息,请访问这里
5. 配置DNS
首先,你可以在/etc/hosts中加入一些主机名称和这些主机名称对应的IP地址,这是简单使用本机的静态查询.
要访问DNS 服务器来进行查询,需要设置/etc/resolv.conf文件.
假设DNS服务器的IP地址是192.168.3.2, 那么/etc/resolv.conf文件的内容应为:
search test.com
nameserver 192.168.3.2
在linux系统中,ssh是远程登录的默认工具,因为该工具的协议使用了RSA/DSA的加密算法.该工具做linux系统的远程管理是非常安全的。 telnet,因为其不安全性,在linux系统中被搁置使用了。
ssh有一套很有用的工具,其中的ssh-keygen可以用来生成 private和public密钥.将生成的public密钥拷贝到远程机器后,可以使ssh到另外一台机器的登陆不用密码.具体方法如下.
1) 在本地机器中的~/.ssh/目录下执行下命令,
ssh-keygen -t dsa
将生成两个文件,id_dsa和 id_dsa.pub.
2) 将id_dsa.pub拷贝到远程机器,并且将id_dsa.pub的内容添加到~/.ssh/authorized_keys中.
cat id_dsa.pub >>authorized_keys
注意:目录.ssh和文件authorized_keys的权限必须是600.
完成这些工作后,用户从本地机器到远程机器的登录就不用密码了.
该设置简单实用.
1. uname -a
2. cat /proc/version
3. cat /etc/issue
4. lsb_release -a #列出所有版本信息
find dir -type d | wc -l 找出dir下所有的子文件夹数.
find dir -type f | wc -l 找出dir下所有子文件子数.
作为自由软件的旗舰项目,Richard Stallman 在十多年前刚开始写作 GCC 的时候,还只是把它当作仅仅一个 C 程序语言的编译器;GCC 的意思也只是 GNU C Compiler 而已。经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言;它现在还支持 Ada 语言、C++ 语言、Java 语言、Objective C 语言、Pascal 语言、COBOL语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而 GCC 也不再单只是 GNU C 语言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU 编译器家族的意思了。另一方面,说到 GCC 对于操作系统平台及硬件平台支持,概括起来就是一句话:无所不在。
1 程序编译过程
GCC是CUI(命令行交互界面)程序,这让许多从Windows走出来 Guier们感到恐惧。实际上它也有许多前端窗口界面,Windows下有Dev C++,Linux下譬如KDevelopment,但既然选择了GCC还是将CUL进行到底吧,没有难与不难的问题,只有做与不做的问题!
下面基于一个具体而微的程序,讨论GCC的使用。示例程序如下:
//test.c
#include <stdio.h>
int main(void)
{
printf(“Hello World!\n”);
return 0;
}
这个程序,一步到位的编译指令是:
gcc test.c -o test
输出的可执行文件名为test,Windows用户可能会感到奇怪,可执行文件明怎么没有.exe扩展名呢?Linux系统中,文件类型并非以扩展名识别的!
实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。
1.1 预处理
运行预处理命令:
gcc -E test.c -o test.i 或 gcc -E test.c
可以输出test.i文件中存放着test.c经预处理之后的代码。打开test.i文件,看一看,就明白了。后面那条指令,是直接在命令行窗口中输出预处理后的代码,而不是以文件作为输出设备。gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将 stdio.h 文件中的内容插入到test.c中了。
gcc的-o选项,用于输出处理结果到文件中。
1.2 编译为汇编代码
预处理之后,可直接对生成的test.i文件编译,生成汇编代码:
gcc -S test.i -o test.s
gcc的-S选项,表示在程序编译期间,在生成汇编代码后,停止,-o输出汇编代码文件。
生成的汇编代码如下:
.file “test.c”
.section .rodata
.align 4
.LC0:
.string “Hello World,Linux programming!”
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident “GCC: (GNU) 4.1.0 20060304 (Red Hat 4.1.0-3)”
.section .note.GNU-stack,”",@progbits
1.3 汇编(Assembly)
如果你学过汇编语言,那么你就该知道程序编译到了这个地步,应当使用汇编器,将汇编语言翻译为机器代码了。这一步尤其重要,因为它决定了你生成的程序,能够运行在哪种机器上。gcc使用的汇编器是gas。
在Intel IA-32平台上,还有一些常用的汇编器有:
* 微软的MASM,这是Intel平台上所有汇编器的鼻祖了,它现在已不是微软的独立产品,只是与Visual Studio捆绑在一起。但微软允许其他组织免费分发MASM 6.0。
* NASM,最初是为UNIX环境开发的商业汇编器,最近成为开源的了,可生成UNIX、MS-DOS和32位Windows格式的可执行文件。
* HLA(high level assembler)是Randall Hyde教授创建的,可以在DOS、Windows和Linux操作系统上生成Intel指令码。但HLA设计的主要目的是向初级程序员讲授汇编语言,学院气太浓,不够实用。
与这些汇编器相比,gas可以在不同处理器平台上工作,通常它可以自动检测底层硬件平台并生成适合该平台的正确机器指令码。gas另一个特性是能够创建不同于程序设计所在平台的指令码,譬如我在Intel计算机上工作,但可以为MIPS计算机写程序。
对于上一小节中生成的汇编代码文件test.s,gas汇编器负责将其编译为目标文件,如下:
gcc -c test.s -o test.o
1.4 连接
gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
对于上一小节中生成的test.o,将其与C标准输入输出库进行连接,最终生成程序test:
gcc test.o -o test
在命令行窗口中,运行test这个小程序,让它说HelloWorld吧!
2、多个程序文件的编译
通常整个程序是由多个源文件组成的,相应地也就形成了多个编译单元,使用GCC能够很好地管理这些编译单元。假设有一个由test1.c和 test2.c两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序test,可以使用下面这条命令:
# gcc test1.c test2.c -o test
如果同时处理的文件不止一个,GCC仍然会按照预处理、编译和链接的过程依次进行。如果深究起来,上面这条命令大致相当于依次执行如下三条命令:
# gcc -c test1.c -o test1.o
# gcc -c test2.c -o test2.o
# gcc test1.o test2.o -o test
需要打这么多编译指令,看着都累,许多Guier们又要抱怨了。的确如此,如果单单使用GCC来编译你的程序,一千个程序源文件的项目编译至少要在命令行窗口中敲1k次文件名,才能完成一次编译。如果代码有了改动,重新编译,需要再原样输入一次编译指令。再技术高超的Cler也会累死的,但是很奇怪,那些Cler们至今依然活的很生龙活虎,这得益于GNU Make工具,详情见Make基础一节。
3、检错
GCC包含完整的出错检查和警告提示功能,可以帮助程序员写出更为标准、健壮的代码。如下面的代码:
//illcode.c
#include <stdio.h>
void main(void)
{
long long int var = 1;
printf(“It is not standard C code!\n”);
printf(“long long int var=%d”,var);
}
这种代码,可能在老的C语言课本里能够见到,但它是不符合ANSI/ISO C语言标准的。我让同学在Visual Stdio .net 2003上编译了一下,没检测出什么问题来。下面看看GCC可不可以:
gcc -pedantic illcode.c -o illcode
输出结果:
illcode.c: 在函数 ‘main’ 中:
illcode.c:5: 警告:ISO C90 不支持 ‘long long’
illcode.c:4: 警告:‘main’ 的返回类型不是 ‘int’
-pedantic编译选项并不能保证被编译程序与ANSI/ISO C标准的完全兼容,它仅仅只能用来帮助Linux程序员离这个目标越来越近。或者换句话说,-pedantic选项能够帮助程序员发现一些不符合 ANSI/ISO C标准的代码,但不是全部,事实上只有ANSI/ISO C语言标准中要求进行编译器诊断的那些情况,才有可能被GCC发现并提出警告。
如果采用默认的编译,即:gcc -pedantic illcode.c -o illcode。输出:
test.c: 在函数 ‘main’ 中:
test.c:4: 警告:‘main’ 的返回类型不是 ‘int’
上面的示例中,long long int是GNU C的扩展类型,表示64位整型数,这种类型没有纳入C/C++标准中,可见GCC默认的编译指令,无法完全检测出不符合标准C/C++的代码,但要比 Visual Stdio .net 2003一声都不吭要好一些。如果使用-pedantic选项,GCC就可以基本上按照标准C/C++进行代码检测了,不要挑剔什么,迄今为止没有任何一款编译器完全支持标准C/C++的。
除了-pedantic之外,GCC还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W开头,其中最有价值的当数-Wall 了,使用它能够使GCC产生尽可能多的警告信息。
GCC给出的警告信息虽然从严格意义上说不能算作错误,但却很可能成为错误的栖身之所。一个优秀的Linux程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮的特性。所以将警告信息当成编码错误来对待,是一种值得赞扬的行为!所以,在编译程序时带上-Werror选项,那么 GCC会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改,如下:
gcc -Werror test.c -o test
输出:
cc1: warnings being treated as errors
test.c: 在函数 ‘main’ 中:
test.c:4: 警告:‘main’ 的返回类型不是 ‘int’
4、库文件连接
人家已经发明了轮子,而且物美价廉,那么我们就实在没有必要浪费生命再去发明同样的轮子!开发软件时,完全不使用第三方函数库的情况是比较少见的,通常来讲都需要借助许多函数库的支持才能够完成相应的功能。从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(so、或lib、 dll)的集合。虽然Linux下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下;Windows所使用的库文件主要放在Visual Stido的目录下的include和lib,以及系统文件夹下。但也有的时候,我们要用的库不再这些目录下,所以GCC在编译时必须用自己的办法来查找所需要的头文件和库文件。
GCC采用搜索目录的办法来查找所需要的文件,-I选项可以向GCC的头文件搜索路径中添加新的目录。例如,如果在 /home/lyanry/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项:
# gcc test.c -I /home/lyanry/include -o test
同样,如果使用了不在标准位置的库文件,那么可以通过-L选项向GCC的库文件搜索路径中添加新的目录。例如,如果在 /home/lyanry/lib/目录下有链接时所需要的库文件libtest.so,为了让GCC能够顺利地找到它,可以使用下面的命令:
# gcc test.c -L /home/lyanry/lib -ltest -o test
上面这条命令中,值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。Linux下的库文件在命名时有一个约定,那就是应该以 lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo 进行处理时,会自动去链接名为libfoo.so的文件。(注:至于在Windows下该怎样连接库文件,未做尝试,以后再谈)
Linux下的库文件分为两大类分别是动态链接库(通常以.so结尾)和静态链接库(通常以.a结尾),二者的区别仅在于程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。动态加载,意味着内存中仅存在一份库代码,所调用的函数只是在调用程序中存在一个映像。而静态加载,意味着将库中所调用的函数代码复制到调用程序中。如果库中存在同名的静态库和动态库,则在默认情况下, GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static选项,强制使用静态链接库。例如,如果在 /home/xiaowp/lib/目录下有链接时所需要的库文件libtest.so和libtest.a,为了让GCC在链接时只用到静态链接库,可以使用下面的命令:
# gcc test.c -L /home/xiaowp/lib -static -ltest -o test
5、优化
代码优化指的是编译器通过分析源代码,找出其中尚未达到最优的部分,然后对其重新进行组合,目的是改善程序的执行性能。GCC 提供的代码优化功能非常强大,它通过编译选项-On来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的GCC来讲,n的取值范围及其对应的优化效果可能并不完全相同,比较典型的范围是从0变化到2或3。
编译时使用选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。
下面通过具体实例来感受一下GCC的代码优化功能,所用程序如下:
//testOpt.c
#include <stdio.h>
int main(void)
{
double counter;
double result;
double temp;
for (counter = 0; counter != 2000.0 * 2000.0 * 2000.0 / 20.0 + 2000; counter += (5 – 1) / 4)
{
temp = counter / 1979;
result = counter;
}
printf(“Result is %lf\n”, result);
return 0;
}
首先不加任何优化选项进行编译:
gcc -Wall testOpt.c -o testOpt
借助Linux提供的time命令,可以大致统计出该程序在运行时所需要的时间:
$time ./testOpt
Result is 400001999.000000
real 0m7.759s
user 0m7.444s
sys 0m0.008s
接下去使用-O1优化选项来对代码进行优化处理:
gcc -Wall -O testOpt.c -o testOpt
测试运行时间:
$time ./testOPt
Result is 400001999.000000
real 0m2.445s
user 0m2.436s
sys 0m0.000s
接下去使用-O2优化选项来对代码进行优化处理:
gcc -Wall -O2 testOpt.c -o testOpt
测试运行时间:
$time ./testOPt
Result is 400001999.000000
real 0m2.338s
user 0m2.320s
sys 0m0.004s
尽管GCC的代码优化功能非常强大,但作为一名优秀的Linux程序员,首先还是要力求能够手工编写出高质量的代码。如果编写的代码简短,并且逻辑性强,编译器就不会做更多的工作,甚至根本用不着优化。特别在以下一些场合中应该避免使用优化:
1. 程序开发的时候优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。
2. 资源受限的时候一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。
3. 跟踪调试的时候对代码进行优化,容易导致某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。
6、程序性能分析
GCC支持的其它调试选项还包括-p和-pg,它们会将剖析(Profiling)信息加入到最终生成的二进制代码中。剖析信息即包含了更为详细的调试信息(只是我这么觉得,由下面的例子可以证实),也对于找出程序的性能瓶颈很有帮助,是协助Linux程序员开发出高性能程序的有力工具。在编译时加入 -p选项会在生成的代码中加入通用剖析工具(Prof)能够识别的统计信息,而 -pg选项则生成只有GNU剖析工具(Gprof)才能识别的统计信息。下面我们还是以crash.c程序的编译和调试,来看看使用-p选项对程序调试的好处吧。
编译:
gcc -Wall -g -p crash.c -o crash
调试:
[lyanry@lyanry crash]$ gdb -q crash
Using host libthread_db library “/lib/libthread_db.so.1″.
(gdb) run
Starting program: /home/lyanry/program/c++/crash/crash
Reading symbols from shared object read from target memory…done.
Loaded system supplied DSO at 0×909000
Input an integer:11
Program received signal SIGSEGV, Segmentation fault.
0×00971667 in _IO_vfscanf_internal () from /lib/libc.so.6
(gdb) backtrace
#0 0×00971667 in _IO_vfscanf_internal () from /lib/libc.so.6
#1 0×00979337 in scanf () from /lib/libc.so.6
#2 0×08048520 in main () at crash.c:8
现在,可以从GDB输出结果中看到带有出错代码行号的backtrace结果了,即#2 0×08048520 in main () at crash.c:8,使用frame指令,查看出错代码,结果如下:
(gdb) frame 2
#2 0×08048520 in main () at crash.c:8
8 scanf(“%d”, input);
现在有点清晰地知道问题发生在哪了吧!
下面,来测试-p或-pg选项用于分析程序的性能瓶颈,结合前面的叙述,看一下man手册上对-p和-pg选项的详细说明:
-p Generate extra code to write profile information suitable for the
analysis program prof. You must use this option when compiling the
source files you want data about, and you must also use it when
linking.
-pg Generate extra code to write profile information suitable for the
analysis program gprof. You must use this option when compiling
the source files you want data about, and you must also use it when
linking.
说明中所提及的prof和gprof,都是程序性能剖析工具,prof是通用的,gprof是GNU开发的。以例程profile.c来测试 gprof,在编译程序时要添加-gp选项。要注意,这个选项只是在连接期间产生作用的。profile.c代码清单如下:
//profile.c
#include <stdio.h>
void function1()
{
int i=0,j;
for(j=0;j<100000;j++)
i+=j;
}
void function2()
{
int i,j;
function1();
for(j=0;j<200000;j++)
i=j;
}
int main(void)
{
int i,j;
for(i=0;i<100;i++)
function1();
for(j=0;i<50000;i++)
function2();
return 0;
}
编译:
gcc -Wall -pg profile.c -o profile
运行profile程序,会在当前目录中生成一个gmon.out文件,下面可以使用gprof工具对profile程序进行剖析了:
gprof profile >gprof.txt
上面指令执行时,gprof会自动使用gmon.out文件,将输出结果重定向到gprof.txt文件中。如果想知道gmon.out是什么,还是看看man手册里的描述吧:
“Gprof” reads the given object file (the default is “a.out”) and establishes the relation between its symbol table and the call graph profile from gmon.out.
好了,现在要做的事情,就是在当前目录下打开gprof.txt,看看了,文件中,我们感兴趣的内容通常有两处:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
66.92 24.44 24.44 49900 489.78 731.38 function2
33.08 36.52 12.08 50000 241.60 241.60 function1
与
index % time self children called name
<spontaneous>
[1] 100.0 0.00 36.52 main [1]
24.44 12.06 49900/49900 function2 [2]
0.02 0.00 100/50000 function1 [3]
———————————————–
24.44 12.06 49900/49900 main [1]
[2] 99.9 24.44 12.06 49900 function2 [2]
12.06 0.00 49900/50000 function1 [3]
———————————————–
0.02 0.00 100/50000 main [1]
12.06 0.00 49900/50000 function2 [2]
[3] 33.1 12.08 0.00 50000 function1 [3]
———————————————–
不想再细说下去,自己琢磨去吧。
//test.c
#include <stdio.h>
int main(void)
{
printf(“Hello World!\n”);
return 0;
}
目前網路上找的的 Cygwin 中文化說明對於新版的 Cygwin 似乎不甚正確,害我之前試了半天都失敗。這次在安裝 Cygwin 時,其 Cygwin DLL 的版號是 1.5.10-1 ,如果一直無法讓 Cygwin 顯示中文字的話,也許可以照以下方式試試看。
初始化 Cygwin
當第一次執行 cygwin 時,多半會出現以下的訊息要求建立使用者:
Your group is currently “mkpasswd”. This indicates that
the /etc/passwd (and possibly /etc/group) files should be rebuilt.
See the man pages for mkpasswd and mkgroup then, for example, run
mkpasswd -l [-d] > /etc/passwd
mkgroup -l [-d] > /etc/group
Note that the -d switch is necessary for domain users.
此時使用以下指令完成使用者建置動作:
mkpasswd -l > /etc/passwd
mkgroup -l > /etc/group
* 若使用者有加入網域中,則要加上 -d 選項,如下例:
mkpasswd -l -d > /etc/passwd
mkgroup -l -d > /etc/group
完成上述指令後,請先離開 Cygwin 環境再重新進入,此時應該會看到 Cygwin 開始建立使用者的基本設定檔:
Copying skeleton files.
These files are for the user to personalise
their cygwin experience.
These will never be overwritten.
`./.bashrc’ -> `/home/bill//.bashrc’ `./.bash_profile’ -> `/home/bill//.bash_profile’ `./.inputrc’ -> `/home/bill//.inputrc’
完成中文化相關設定
當完成上述設定後,Cygwin 才會建立使用者的基本設定,此時才能依照網路上所找到的方式完成 Cygwin 中文化設定。
1. 編輯 ~/.inputrc ,加入以下設定:
set meta-flag on
set input-meta on
set convert-meta off
set output-meta on
2. 編輯 ~/.bash_profile ,加入以下設定:
alias ls=’ls –show-control-chars’
Analytics Plugin created by Web Hosting