linux c内存分配方式以及动态内存分配

从静态存储区分配(由系统控制)

内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,staic变量

在栈上分配(由系统控制)

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。效率很高,凡事分配的内存容量有限

在堆上分配,亦称动态内存分配(由自己控制)

程序在运行时用malloc等函数申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生命周期有我们自己决定,使用非常灵活,但问题也最多

malloc函数

void *malloc(size_t size);

  • 使用:需要包含malloc.h头文件
  • 功能:允许从空闲内存池中分配连续内存但不初始化
  • 参数:size参数是一个所需字节
  • 返回:若分配成功则返回一个指向该内存块的指针,在使用时可根据需要做强制类型转换,否则返回NULL指针
calloc函数

void *calloc(size_t num_elements,size_t element_size);

  • 使用:需要包含malloc.h头文件
  • 功能:功能与malloc函数相同,但作初始化
  • 参数:num_elements是所需元素的数量,element_size是每个元素的字节
  • 返回:与malloc相同
realloc含糊

void *realloc(void *ptr,size_t new_size)

  • 使用:需要包含malloc.h头文件
  • 功能:在指针ptr指向的内存基础上扩大或缩小内存
  • 参数:ptr是指向先前通过malloccallocrealloc函数后分配的内存块的指针,new_size是内存块的新尺寸,可能大于或小于原有内存尺寸
  • 返回:若能调整内存大小则返回指向调整后内存的指针,否则返回NULL
realloc函数的使用注意点
  • 当扩展内存时,不会对添加的内存块的字节进行初始化
  • 弱不能调整内存则返回NULL,但原有内存中的数据不会发生改变
  • 若第一个参数为NULL那么功能等同于malloc函数,若第二个参数为0,那么会释放调用内存块。
  • 在缩小或扩大内存时一般不会对其进行移动,若无法扩大内存块(内存块后面的字节已经用于其他木的),那么可能会在别处分配心的内存块,然后把旧块的数据复制到新块中,并将旧块删除释放内存
free函数

void free(void *ptr);

  • 功能:释放由指针ptr指向的动态内存分配的内存块
free函数注意点
  • 如果ptrNULL指针,那么freeptr无论操作多少次都不会出问题
  • 如果ptr不是NULL指针,那么freeptr连续操作两次就会导致程序停止运行

示例

// stdlib会包含malloc
#include <stdlib.h>
#include <stdio.h>
void print_arr(int *p,int length);
int main(void)
{
        size_t length = 0;
        scanf("%d",&length);
        if(length > 0)
        {
                // 使用malloc分配内存
                //int *p = (int*)malloc(length);
                // 使用calloc分配内存
                int *p = (int*)calloc(sizeof(int),length);
                p[0] = 8;
                print_arr(p,length);
                // 使用 realloc修改申请的内存空间的大小
                p = realloc(p,length + 2);
                print_arr(p,length + 2);
                free(p);
                // 注意虽然释放了申请的内存,但是这个注意要清空下指针
                p = NULL;
        }
        return 0;
}
void print_arr(int *p,int length)
{
        for(int i = 0;i < length;i++)
        {
                printf("p[%d] = %d;\n",i,p[i]);
        }
}

gdb core 使用流程

打开core dump开关

查看core文件大小,系统默认为0

ulimit -c

设置core文件的大小,单位为kbyte

ulimit -c size

设置core文件存储位置
查看core文件存储位置,默认回存存储到当前目录的core.进程id

cat /proc/sys/kernel/core_pattern

设置core文件位置

echo "/tmp/core.%e.%p.%t" > /proc/sys/kernel/core_pattern

编译程序加上-g选项

gcc -g -o 可执行文件 源文件

运行可执行文件

运行过程中如果有问题会产生core文件

定位段错误位置

使用gdb载入调试程序和问题发生时产生的core文件

gdb 可执行文件 core文件

gdb高级命令

工作环境相关命令

命令格式含义
set args 运行时的参数指定运行时的参数,如 set args 2
show args查看设置好的运行参数
path dir设定程序的运行路径
show paths查看程序的运行路径
set environment var[=value]设置环境变量
set var=value修改运行时变量的值
show environment [var]查看环境变量
cd dir进入到dir目录,相当于shell中的cd命令
pwd显示当前工作目录
shell command运行shell的command命令

设置断点和恢复命令

命令格式含义
info b查看所设置的断点
break(b) [行号|函数名] <条件表达式>设置断点
tbreak(b) [行号|函数名] <条件表达式>设置临时断点,到达后自动删除
delete [断点号]删除指定断点
disable [断点号]停止指定的断点名,使用info b仍然能查看此断点。同delete一样,省略断点号则停止所有断点
enable [断点号]激活指定断点,省略则激活所有断点号
condition [断点号] <条件表达式>修改对应断点的条件
ignore [断点号] <num>在程序执行时,忽略对应断点n次
step(s)单步恢复程序运行,且进入函数调用
next(n)单步恢复程序运行,但不会进入函数调用
until(u) 行号跳到指定行
finish运行程序,直到当前函数完成返回
continue(c)继续执行函数,直到函数结束或遇到新的断点

查看源码相关命令

命令格式含义
list(l) <行号>|><函数名>查看指定位置代码
file [文件名]加载指定文件
forward-search 正则表达式源代码前后搜索
reverse-search 正则表达式源代码向前搜索
show directories显示定义了的源文件搜索路径
info file显示加载到gdb内存中的代码
disassemble 函数名查看指定函数的反汇编代码

查看运行数据相关命令

命令格式含义
print(p) 表达式|变量查看程序运行时对应表达式和变量的值
x /<n/f/u> <addr>查看内存变量内容。其中n为整数表示显示内存的长度,f表示显示的格式(如:d表示十进制,x表示16进制,o表示八进制,t表示二进制),u表示从当前的地址往后请求显示的字节数,<addr>表示变量的内存的地址
display 表达式设定在单步运行或其他情况中,自动显示的对应表达式的内容(如:display /i $pc 显示c代码和汇编代码)

操作实例

添加删除断点
(gdb) b 5 # 在第五行加个断点
Breakpoint 1 at 0x400483: file src/gdb_test.c, line 5.
(gdb) info b # 查看所有的断点的信息
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400483 in main at src/gdb_test.c:5
(gdb) delete 1 # 根据断点的编号删除断点
(gdb) info b # 再次查看,可以发现断点已经没了
No breakpoints or watchpoints.
打印变量
(gdb) p a
$1 = 1
(gdb) p &a
$2 = (int *) 0x7fffffffe454
(gdb) x /d 0x7fffffffe454 # 十进制方式输出
0x7fffffffe454:    1
(gdb) x /x 0x7fffffffe454 # 十六进制输出
0x7fffffffe454:    0x00000001
(gdb) x /o 0x7fffffffe454 # 八进制输出
0x7fffffffe454:    01
(gdb) x /t 0x7fffffffe454 # 二进制输出
0x7fffffffe454:    00000000000000000000000000000001

curl检测Web 站点的响应时间

命令:

curl -o /dev/null -s -w %{time_connect}:%{time_starttransfer}:%{time_total} http://jinblog.com
2.554:2.984:3.040

输出通常是 HTML 代码。

参数:

-o 参数发送到 /dev/null。
-s 参数去掉所有状态信息。
-w 参数让 curl 写出表 1 列出的计时器的状态信息:
计时器 描述
time_connect 建立到服务器的 TCP 连接所用的时间
time_starttransfer 在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
time_total 完成请求所用的时间

以上计时器都相对于事务的起始时间,甚至要先于 Domain Name Service(DNS)查询。

因此,在发出请求之后,Web 服务器处理请求并开始发回数据所用的时间是 0.272 - 0.081 = 0.191 秒。

客户机从服务器下载数据所用的时间是 0.779 - 0.272 = 0.507 秒。

通过观察 curl 数据及其随时间变化的趋势,可以很好地了解站点对用户的响应性。

转载自 http://www.jbxue.com/LINUXjishu/13381.html

objdump命令的使用

objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它还有其他作用,下面以ELF格式可执行文件test为例详细介绍:

objdump -f test
显示test的文件头信息

objdump -d test
反汇编test中的需要执行指令的那些section

objdump -D test
与-d类似,但反汇编test中的所有section

objdump -h test
显示test的Section Header信息

objdump -x test
显示test的全部Header信息

objdump -s test
除了显示test的全部Header信息,还显示他们对应的十六进制文件代码

举例:

将C源代码和反汇编出来的指令对照:

  1. 编译成目标文件(要加-g选项)
    gcc -g -o test.c
  2. 输出C源代码和反汇编出来的指令对照的格式
    objdump -S test.o

如下:

00000000004004c4 <main>:
#include <stdio.h>
#define ARR_LENGTH 3
int main(void)
{
  4004c4:    55                       push   %rbp
  4004c5:    48 89 e5                 mov    %rsp,%rbp
  4004c8:    48 83 ec 30              sub    $0x30,%rsp
    int a=1,b=2,c=3,*p[ARR_LENGTH] = {&a,&b,&c};
  4004cc:    c7 45 f8 01 00 00 00     movl   $0x1,-0x8(%rbp)
  4004d3:    c7 45 f4 02 00 00 00     movl   $0x2,-0xc(%rbp)
  4004da:    c7 45 f0 03 00 00 00     movl   $0x3,-0x10(%rbp)
  4004e1:    48 8d 45 f8              lea    -0x8(%rbp),%rax
  4004e5:    48 89 45 d0              mov    %rax,-0x30(%rbp)
  4004e9:    48 8d 45 f4              lea    -0xc(%rbp),%rax
  4004ed:    48 89 45 d8              mov    %rax,-0x28(%rbp)
  4004f1:    48 8d 45 f0              lea    -0x10(%rbp),%rax
  4004f5:    48 89 45 e0              mov    %rax,-0x20(%rbp)
    for(int i = 0;i < ARR_LENGTH;i++)
  4004f9:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%rbp)
  400500:    eb 27                    jmp    400529 <main+0x65>
    {
        printf("*p[%d] = %d\n",i,*p[i]);
  400502:    8b 45 fc                 mov    -0x4(%rbp),%eax
  400505:    48 98                    cltq   
  400507:    48 8b 44 c5 d0           mov    -0x30(%rbp,%rax,8),%rax
  40050c:    8b 10                    mov    (%rax),%edx
  40050e:    b8 38 06 40 00           mov    $0x400638,%eax
  400513:    8b 4d fc                 mov    -0x4(%rbp),%ecx
  400516:    89 ce                    mov    %ecx,%esi
  400518:    48 89 c7                 mov    %rax,%rdi
  40051b:    b8 00 00 00 00           mov    $0x0,%eax
  400520:    e8 93 fe ff ff           callq  4003b8 <printf@plt>