首页 > 其他分享 >《后台开发:核心技术与应用实践》第五章 核心技术与应用实践

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践

时间:2023-05-07 17:31:57浏览次数:51  
标签:strace 核心技术 coredump 实践 int 内存 应用 printf test


文章目录

  • 一、基础知识
  • 二、strace
  • 1.基础知识
  • 2.strace:跟踪系统调用来让开发者知道一个程序在后台做什么事情
  • (1)strace基本用法
  • (2)strace跟踪信号传递
  • (3)统计系统调用:strace -c XXXX
  • (5)输出到其他文件:strace -o XXX
  • (6)每个系统调用所花费的时间:strace -T XXX
  • (7)记录系统调用发生的时间:strace -t XXX
  • (8)strace追踪现有进程:strace -p PID
  • (10)strace调试程序
  • 三、gdb
  • 1.基础知识
  • (2)gcc和g++的-g参数:将调试信息加到可执行文件中
  • 2.gdb基本用法
  • 3.用gdb分析coredump文件
  • (1)gdb分析coredump文件的基础知识
  • (b)coredump 文件的存储路径
  • (c)有时候,执行程序提示Segmentation fault,但是没生成 coredump 文件,解决手段如下:
  • (i)ulimit -c 命令可以查看 coredump 文件大小的最大值。
  • (ii)当前用户执行对应程序的用户具有对写人 core 目录的写权限以及有足够的空间
  • (iii)产生 coredump 文件的常见原因
  • (2)用gdb定位coredump文件
  • readelf -h XXX
  • objdump -x
  • gdb XXX
  • 三、top:实时显示各进程的资源占用状态,类似于windows资源管理器
  • 1.top命令的结果说明
  • 2.top命令的总结
  • 四、ps:当前在运行的进程的快照
  • 1.top与ps的区别
  • 2.kill 命令用于杀死进程
  • (1)Linux上进程的5种状态
  • (2)ps 工具标识进程的 5 种状态码
  • 3.ps命令的常用参数
  • (1)ps 命令常用参数
  • (3)显示指定用户信息 :ps -u XXX
  • (4)显示所有进程信息,连同命令行 :ps -ef
  • (5)ps 与 grep 常用组合用法, 查找特定进程 :ps -ef | grep XXX
  • (6)将目前登人的 PID 与相关信息列示出来 :ps -I
  • (7)列出目前所有的正在内存当中的程序:ps aux
  • 五、Valgrind:内存分析工具
  • 1.Valgrind简介
  • (3)Memcheck的内存检查原理
  • (4)Valgrind 安装
  • (5)Valgrind 使用
  • (a)用 Valgrind 来分析代码的内存使用
  • (b)用 Valgrind 来分析使用未初始化程序的内存
  • (c)用 Valgrind 来分析内存读写越界
  • (d)内存覆盖
  • (e)动态内存管理错误
  • (i)3种常见的内存分配方式:静态存储、栈上分配、堆上分配
  • (ii)常见的内存动态管理错误有:
  • (f)内存泄漏
  • 2.Linux程序的内存空间布局
  • (1)典型的 Linux 的运行中的C程序的内存空间布局
  • (2)堆与栈的区别
  • 查看栈大小的限制:ulimit -a
  • 修改栈的大小:ulimit -s
  • (3)eg来分析变量和内存的地址

一、基础知识

调试的方法一般分为以下两种:

  • (1)在程序中插入打印语句,优点是能够显示程序的动态过程,比较容易检查源程序的
    有关信息 。 缺点是效率低,可能输入大量无关的数据,发现错误具有偶然性 。
  • 2)借助调试工具。 目前大多数程序设计语言都有专门的调试工具,比如 C++的调试工具有 GDB ,可以用这些工具来分析程序的动态行为 。

二、strace

1.基础知识

(1)应用程序是不能直接访问 Linux 内核的 。 它既不能访问内核所占内存空间,也不能调用内核函数。
具体做法是:

  • 应用程序可以跳转到 system_call 的内核位置,内核会检查系统调用号,这个号码会告诉内核进程正在请求哪种服务。
  • 然后,它查看系统调用表,找到所调用的内核函数人口地址,调用该函数,然后返回到进程。

(2)所有操作系统在其内核都有一些内建的函数,一般称 Linux 系统上的这些函数为“系统调用”( system call )。 这些函数代表了用户空间到内核空间的一种转换。
eg:在用户 空间调用 open 函数,在内核空 间则会调用 sys_open 。

(3)系统调用的错误码:系统调用并不直接返回错误码,而是将错误码放入一个名为 errno
的全局变量中 。

  • errn不同数值所代表 的错误消息定义在 errno.h 中,你也可以通过命令”man 3 errn。”来查看它们 ;
  • 需要注意的是 , errno 的值只在函数发生错误时设置,如果函数不发生错误, errno 的值
    就无定义 ,并不会被置为 0

2.strace:跟踪系统调用来让开发者知道一个程序在后台做什么事情

(1)strace基本用法

(a)输入一个数,并输出这个数 。

#include 	<iostream>
using namespace;
int main(void)
{
	int a;
	cin>>a;
	cout<<a<<endl;
	
	return	0;
}

(b)然后用 g++ test.cpp -o test 编译一下,得到一个可执行文件 test ,执行结果如图 5-1 所示 。

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios


(c)strace ./test

  • 每一行都是一次系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。
    -整体执行过程如下:



    执行细节如下:
    (i)





    (ii)如果出错,数组等其他其他情况,strace 常用的系统调用会出现的结果

(2)strace跟踪信号传递

  • 还是先输入命令“ strace ./test ”,等待的时候不要输入任何东西,然后打开另外一个窗口,输入命令“ killall test ;
  • strace 中的结果显示 test 进程“+++ killed by SIGTERM +++” 。 事实上,命令 kiillall test ,就是杀死所有名为 test 的进程。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_02


  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_03


(3)统计系统调用:strace -c XXXX

  • 过使用参数- c ,它还能将进程所有的系统调用做一个统计分析井返回 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_04

  • (4)用 strace 统计 scanf输入 printf 输出
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_05


(5)输出到其他文件:strace -o XXX

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_06

(6)每个系统调用所花费的时间:strace -T XXX

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_07


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_08

(7)记录系统调用发生的时间:strace -t XXX

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_09

(8)strace追踪现有进程:strace -p PID

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_10

(10)strace调试程序

调试的代码如下:

#include <iostream>  
#include <fstream>  
#include <stdlib.h>
using namespace std;  
int main(){  
   char buffer[256];  
   ifstream in("input.txt");  
   if (! in.is_open()){
       cout << "Error opening file"<<endl;
       exit (1);
   }  
   while (!in.eof()){  
       in.getline (buffer,100);  
       cout << buffer << endl;  
    }  
  return 0;  
}

(a)代码运行及解释
例 5.3 中的程序是从当前目录下的 input.txt 中读取内容,然后把它输出 。 当执行./test 命令,结果如图 5-11 所示。

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_11

结果提示 Error opening file ,也就是读取文件时出现了异常,那究竟是什么异常呢,我们可以继续用 strace 来定位 。

执行 strace ./test 命令后,结果如图 5-12 所示(只截取了后面部分)。

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_12

三、gdb

1.基础知识

(1)gdb 是 gcc 的调试工具,主要用于 C 和 C++这两种语言编写的程序,主要功能有以下4个:

  • ①启动程序,可以按照用户自定义的要求随心所欲地运行程序,
  • ②可让被调试的程序在指定的断点处停住;
  • ③当程序被停住时,可以检查此时程序中运行的状态;
  • ④动态地改变程序的执行环境 。

(2)gcc和g++的-g参数:将调试信息加到可执行文件中

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_13


(3)启动gdb的方法

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_14

2.gdb基本用法

(1)需要调试的cpp代码如下:

#include<iostream>
using namespace std;
int func(int n){
    int result=0;
    for(int i=1;i<=n;i++){
        result+=i;
    }
    return result;
}
int main(){
    int arr[10];
    arr[0]=0;
    arr[1]=1;
    for(int i=2;i<10;i++){
        arr[i]=arr[i-1]+arr[i-2];
    }
    cout<<"arr[9]"<<arr[9]<<endl;
    cout<<"func(9)"<<func(9)<<endl;
    return 0;
}
  • 用g++ -g test.cpp -o test命令编译程序,注意这里要加上也。 程序的执行结果如图 5-14所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_15

  • 接下来用 gdb 调试程序,输入 gdb test 命令,启动 gdb 。 执行结果如图 5-15 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_16

  • 输入” l “后( l 命令相当于 list),从第一行开始列出源码,结果如图 5-16 所示 。再按下 Enter 键,表示重复上一次命令,结果如图 5-17 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_17

  • 执行“ b 15”,表示设置在源码 15 行处设置断点,执行“ b func ”,表示设置断点在函数func 入口处,执行“ info break ,,,表示查看断点的信息,如图 5” 18 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_18

  • 执行 r 命令,表示运行程序, run 命令简写,如图 5-19 所示 。图 5-19 表示,程序停在了断点处 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_19

  • 输入“ n ”,表示单条语句执行, next 命令简写,如图 5-20 所示 。

  • 输入“ p i”“ p arr[i]”,分别打印变量 i 和变量 a盯[i]的值,如图 5-21 所示 。

  • 输入“ bt ”,查看函数堆栈,如图 5-22 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_20

  • 输入“ finish ,退出函数,如图 5-23 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_21

  • 程序结束时如图 5-24 所示 。输入“ q ”,结束调试,如图 5-25 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_22


  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_23

(2)上述一共用了以下这些命令 。

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_24


3.用gdb分析coredump文件

(1)gdb分析coredump文件的基础知识

(a)core ,又称之为 coredump 文件,是 UNIX/Linux 操作系统的一种机制。coredump 文件含有当进程被终止时内存、 CPU 寄存器和各种函数调用堆械信息等,可以供后续开发人员进行调试 。

(b)coredump 文件的存储路径

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_25


更改 coredump 文件的存储位置的操作如下:

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_26


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_27

(c)有时候,执行程序提示Segmentation fault,但是没生成 coredump 文件,解决手段如下:

(i)ulimit -c 命令可以查看 coredump 文件大小的最大值。

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_28

(ii)当前用户执行对应程序的用户具有对写人 core 目录的写权限以及有足够的空间

保证以上两点后,再执行文件,就会发现 coredump 时的提示变成了如图 5-29 所示的情况。
提示 Segmentation fault (core dumped),接着就只需去 cat /proc/sys/kernel/core_pattern 输
出的目录下找到该 coredump 文件即可 。

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_29

(iii)产生 coredump 文件的常见原因

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_30


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_31


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_32

(2)用gdb定位coredump文件

(a)非法访问内存的eg

#include <stdio.h>
int main(){
    int b=1;
    int* a;
    *a=b;
    return 0;
}
  • 用 g++ -g -o test test.cpp 编译该文件,得到 test 这个可执行文件。 执行 ./test 命令后,结果如图 5-30 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_33


readelf -h XXX

  • 对程序进行 coredump 后,把 coredump 文件放到当前目录下以备分析,先来看下该 coredump文件的 ELF 头部(readelf -h直接从字面意思去记命令),如图 5-31 所示 。但是 core 文件中没有符号表信息,无法进行调试
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_34


objdump -x

  • 用 objdump 命令查看 coredump文件的符号表
    指令:objdump -x core.test . 13093 I tail
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_35


gdb XXX

  • 接着来看下是 core 在哪了 。 执行 gdb test core.test.13093 命令后结果如图33 所示 。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_36


  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_37


三、top:实时显示各进程的资源占用状态,类似于windows资源管理器

1.top命令的结果说明

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_38


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_39


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_40

2.top命令的总结

  • 比较准确地说, top 命令提供了实时地对系统处理器的状态监视。 它将显示系统中 CPU
    最“敏感”的任务列表。 该命令可以按 CPU 使用 、 内存使用和执行时间对任务进行排序;而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定 。
  • 输入“ q”,则退出 top 命令。
四、ps:当前在运行的进程的快照

1.top与ps的区别

  • Linux 中的 ps (process status )命令列出的是当前在运行的进程的快照,就是执行 ps 命
    令的那个时刻的那些进程,如果想要动态地显示进程信息,就可以使用 top 命令 。
  • ps 命令提供进程的一次性的查看,它所提供的查看结果并不动态连续的;如果想对进程
    时间监控,应该用 top 命令 。

2.kill 命令用于杀死进程

(1)Linux上进程的5种状态

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_41

(2)ps 工具标识进程的 5 种状态码

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_42

3.ps命令的常用参数

(1)ps 命令常用参数

  • 命令格式是: ps[参数] 。 命令功能是用来显示当前进程的状态 。
  • 常用参数如下
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_43

  • (2)eg
#include<iostream>
using namespace std;
int main(){
    for(int i=0;i<100;i++){
        cout<<"i:"<<i<<endl;
        sleep(5);
    }
    return 0;
}

程序的执行结果如图 5-36 所示。例 5.7 中,是利用 for 循环打印一个数字,每打一次就休眠缸,一共打印 100 次。

(3)显示指定用户信息 :ps -u XXX

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_44


其中的 test 进程,正是刚刚手动运行的那个 。

(4)显示所有进程信息,连同命令行 :ps -ef

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_45

(5)ps 与 grep 常用组合用法, 查找特定进程 :ps -ef | grep XXX

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_46

(6)将目前登人的 PID 与相关信息列示出来 :ps -I

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_47


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_48

(7)列出目前所有的正在内存当中的程序:ps aux

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_49


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_50

五、Valgrind:内存分析工具

1.Valgrind简介

(1)

  • Valgrind 是一套 Linux 下的开放源代码的仿真调试工具的集合。
  • Valgrind 由内核以及基于内核的其他调试工具组成。 内核类似于一个框架,它模拟了一个 CPU 环境,并提供服务给其他工具;而其他工具则类似于插件,利用内核提供的服务完成各种特定的内存调试任务 。

(2)Valgrind 体系结构图

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_51


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_52

(3)Memcheck的内存检查原理

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_53


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_54

(4)Valgrind 安装

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_55

(5)Valgrind 使用

(a)用 Valgrind 来分析代码的内存使用

#include<iostream>
#include<stdlib.h>
using namespace std;
void func(){
    int *x=(int *)malloc( 10 * sizeof ( int ) ) ;
    x[10]=0;
}
int main(){
    func();
    cout<<"done"<<endl;
    return 0;
}

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_56


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_57


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_58


总结:

该程序有 2 个问题:

  • ① fun 函数中动态申请的堆内存没有释放;
  • ②对堆内存的访问越界 。

(b)用 Valgrind 来分析使用未初始化程序的内存

  • 对于位于程序中不同段的变量,其初始值是不同的,全局变量和静态变量初始值为 0;
  • 而局部变量和动态申请的变量,其初始值为随机值。

eg说明:数组 a 是局部变量,其初始值为随机值,而在初始化时并没有给其所有数组成员初始化,如此在接下来使用这个数组时就潜在有内存问题。

#include<iostream>
using namespace std;
int main(){
    int a[5];
    int i,s=0;
    a[0]=a[1]=a[3]=a[4]=0;
    for(i=0;i<5;i++)
            s=s+a[i];
    if(s==33)
            cout<<"sum is 33"<<endl;
    else
            cout<<"sum is not 33"<<endl;
    return 0;
}

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_59

(c)用 Valgrind 来分析内存读写越界

  • 内存读写越界是指访问了没有权限访问的内存地址空间,比如访问数组时越界、对动态内存访问时超出了申请的内存大小范围 。

eg说明:
下面的程序例 5.11 就是一个典型的数组越界问题。pt 是一个局部数组变量,其大小为 4, p 初始指向 pt 数组的起始地址,但在对 p 循环叠加后,p 超出了 pt 数组的范围,如果此时再对 p 进行写操作,那么后果将不可预期。

#include<stdlib.h>
#include<iostream>
using namespace std;
int main(){
    int len=4;
    int *pt=(int *)malloc(len*sizeof(int));//堆内存的大小是16byte,即4个int的大小
    int *p=pt;
    for(int i=0;i<len;i++)
            p++;
    *p=5;//非法写
    cout<<"the value of p is "<<*p<<endl;//非法读
    return 0;
}

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_60

(d)内存覆盖

  • **C 语言的强大和可怕之处在于其可以直接操作内存,**比如 strcpy , stmcpy 、 memcpy, strcat 等,这些函数有一个共同的特点就是需要设置源地址(src)和目标地址(dst),且 src 和 dst 指向的地址不能发生重叠,否则结果将不可预期 。

eg如下:

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_61


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_62


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_63

(e)动态内存管理错误

(i)3种常见的内存分配方式:静态存储、栈上分配、堆上分配
  • 全局变量属于静态存储,它们是在编译时就被分配了存储空间;
  • 函数内的局部变量属于栈上分配;
  • 最灵活的内存使用方式是:堆上分配,也叫做内存动态分配, 常见的内存动态分配函数包括:malloc、alloc、realloc、new等,动态释放函数包括:free和delete等
(ii)常见的内存动态管理错误有:

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_64


(iii)eg如下:

#include<iostream>
#include<stdlib.h>
int main(){
    int i;
        char *p= (char *)malloc(10);
        char *pt=p;
        for(i=0;i<10;i++){
                p[i]='z';
        }
        delete p;//按照理解,这是第11行
        pt[1]='x';//按照理解,这是第12行
        free(pt);//按照理解,这是第13行

    return 0;
}

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_65


执行以下命令:/home/sharexu/software/valgrind/bin/valgrind …tool=memcheck ./test

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_66


这时候可以顺便用 GDB 来逐行看下究竟是哪一行导致程序处于 coredump 状态的 。

先在程序第 10 、 11 、 12 、 13 、 14 行设置断点,如图 5-53 所示 。

  • 然后运行程序,可见是在程序第 13 行时程序 coredump 了, free(pt)语句释放了无效的内存。
    程序非法读写内存都不一定会出现 coredump ,但释放无效内存则一定会出现 coredump。
  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_67


  • 《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_68


(f)内存泄漏

  • 内存泄漏memory leak指的是,在程序中动态申请的内存,在使用完后既没有释放,也无法被程序的其他部分访问。
  • 防止内存泄漏除了要从良好的编程开始,还要加强单元测试unite test

eg:
tree.h的代码如下:

#ifndef _TREE_
#define _TREE_
typedef struct _node{
     struct _node *l;
     struct _node *r;
     char v;    
}node;
node *mk(node *l, node *r, char val);
void nodefr(node *n);
#endif

tree.cpp的代码如下:

#include<stdlib.h>
#include"tree.h"
node *mk(node *l,node *r,char val){
     node *f=(node *)malloc(sizeof(*f));
     f->l=l;
     f->r=r;
     f->v=val;
     return f;    
}
void nodefr(node *n){
     if(n){
          nodefr(n->l);
          nodefr(n->r);
          free(n);
     }
}

test.cpp 的代码是:

#include<iostream>
#include"tree.h"
int main(){
     node *tree1,*tree2,*tree3;
     tree1=mk(mk(mk(0,0,'3'),0,'2'),0,'1');
     tree2=mk(0,mk(0,mk(0,0,'6'),'5'),'4');
     tree3=mk(mk(tree1,tree2,'8'),0,'7');
     return 0;    
}

makefile 的代码是:

test: test.o tree.o
	g++ -g -o test test.o tree.o
tree.o:tree.cpp tree.h
	g++ -g -c tree.cpp -o tree.o
test.o:test.cpp
	g++ -g -c test.cpp -o test.o

运行结果如下:

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_69


解释如下:

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_70


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_71


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_72


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_73

2.Linux程序的内存空间布局

(1)典型的 Linux 的运行中的C程序的内存空间布局

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_74


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_75


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_76

(2)堆与栈的区别

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_77

查看栈大小的限制:ulimit -a

修改栈的大小:ulimit -s

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_78


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_79

(3)eg来分析变量和内存的地址

#include<stdio.h>
#include<stdlib.h>
int g1=0, g2=0, g3=0;
int max(int i)
{
    int m1=0,m2,m3=0,*p_max;
    static int n1_max=0,n2_max,n3_max=0;
    p_max = (int*)malloc(10);
    printf("打印max程序地址\n");
    printf("in max: %x\n\n",max);
    printf("打印max传入参数地址\n");
    printf("in max: %x\n\n",&i);
    printf("打印max函数中静态变量地址\n");
    printf("%x\n",&n1_max); //打印各本地变量的内存地址
    printf("%x\n",&n2_max);
    printf("%x\n\n",&n3_max);
    printf("打印max函数中局部变量地址\n");
    printf("%x\n",&m1); //打印各本地变量的内存地址
    printf("%x\n",&m2);
    printf("%x\n\n",&m3);
    printf("打印max函数中malloc分配地址\n");
    printf("%x\n\n",p_max); //打印各本地变量的内存地址
    if(i) return 1;
    else return 0;
}
int main(int argc, char **argv)
{
    static int s1=0, s2, s3=0;
    int v1=0, v2, v3=0;
    int *p;   
    p = (int*)malloc(10);
    printf("打印各全局变量(已初始化)的内存地址\n");
    printf("%x\n",&g1); //打印各全局变量的内存地址
    printf("%x\n",&g2);
    printf("%x\n\n",&g3);
    printf("======================\n");
    printf("打印程序初始程序main地址\n");
    printf("main: %x\n\n", main);
    printf("打印主参地址\n");
    printf("argv: %x\n\n",argv);
    printf("打印各静态变量的内存地址\n");
    printf("%x\n",&s1); //打印各静态变量的内存地址
    printf("%x\n",&s2);
    printf("%x\n\n",&s3);
    printf("打印各局部变量的内存地址\n");
    printf("%x\n",&v1); //打印各本地变量的内存地址
    printf("%x\n",&v2);
    printf("%x\n\n",&v3);
    printf("打印malloc分配的堆地址\n");
    printf("malloc: %x\n\n",p);
    printf("======================\n");
    max(v1);
    printf("======================\n");
    printf("打印子函数起始地址\n");
    printf("max: %x\n\n",max);
    return 0;
}

《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_ios_80


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_81


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_系统调用_82


《后台开发:核心技术与应用实践》第五章 核心技术与应用实践_#include_83




标签:strace,核心技术,coredump,实践,int,内存,应用,printf,test
From: https://blog.51cto.com/u_12740336/6252281

相关文章

  • C++虚函数详解:多态性实现原理及其在面向对象编程中的应用
    在面向对象的编程中,多态性是一个非常重要的概念。多态性意味着在不同的上下文中使用同一对象时,可以产生不同的行为。C++是一种面向对象的编程语言,在C++中,虚函数是实现多态性的关键什么是虚函数虚函数是一个在基类中声明的函数,它可以被子类重写并提供不同的实现。在C++中,使用关......
  • PG数据库生态选型思路与最佳实践
    PG数据库生态选型思路与最佳实践2021-03-29 1157举报简介: PG数据库生态选型思路与最佳实践内容简要:1. 数据库发展的趋势2. 传统企业级数据库选型3. 数据库迁移的最佳实践4. 数据库迁移至PG整体解决方案   第一部分--数据库的发展趋势 数据库......
  • spring-boot-2.0.3应用篇 - shiro集成
    spring-boot-2.0.3应用篇-shiro集成  前言      上一篇:spring-boot-2.0.3源码篇-国际化,讲了如何实现国际化,实际上我工作用的模版引擎是freemaker,而不是thymeleaf,不过原理都是相通的。      接着上一篇,这一篇我来讲讲spring-boot如何整合工作中用到的......
  • 原型设计工具比较及实践
    目录一:原型设计工具比较:1.墨刀2.Axure3.Mockplus二、原型设计1.主题名称2.功能3.界面设计考虑因素4.切换界面5.切换界面流程一:原型设计工具比较:1.墨刀适用领域墨刀是一款打通产设研团队,实现原型,设计,流程,思维导图一体化的在线协同工具。从记录想法的思维导图开始,到原型绘......
  • Linux系列---【如何根据端口号确定应用是否已启动?并根据端口号定位到程序所在的目录?】
    如何根据端口号确定应用是否已启动?并根据端口号定位到程序所在的目录?方法一(lsof命令)#注意:没有该命令先执行安装命令yuminstalllsof#查看端口是否被占用lsof-i:7080如图,输完没有反应,说明端口未被占用,即应用未启动如图,输完如果有反应,寿命端口已占用,使用pwdx+pid命令即可......
  • 2022最简单方法更新华为鸿蒙3.0系统HarmonyOS 3.0安装谷歌服务框架GMS谷歌应用商店Goo
    原视频:https://www.youtube.com/watch?v=AsAiuMKXOQYGbox谷歌框架官方下载地址:https://www.gboxlab.com/Gbox谷歌框架带谷歌应用商店的旧版本下载:https://www.mediafire.com/file/sj0l50pogpjwjnb/GBox-release-1.3.20.apk/file......
  • CUDA编程 基础与实践 樊哲勇 电子书 pdf
    作者:樊哲勇出版社:清华大学出版社出版年:2020-10 关注公众号:红宸笑。回复:电子书即可  CUDA是目前较为流行的GPU高性能计算的开发工具之一。本书通过大量实例系统地讲述CUDA编程的重要方面。前12章通过一些简短的例子循序渐进地介绍CUDA编程的基础知识,主要包......
  • Java中栈的创建与其常见的应用场景
    (1)Java中栈的创建方式①使用Stack类Java提供了最容易根据名字想起的Stack类,这也是在Java6以及更早版本常用的方式。Stack<String>stack=newStack<>();//创建一个栈,泛型为String,一般来讲String作为泛型是很安全的stack.push("AAAI");stack.push("KDD");stack......
  • 【Azure 应用服务】Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无
    问题描述开发AzureJSFunction(NodeJS),使用mssql组件操作数据库。当SQL语句执行完成后,在Callback函数中执行日志输出 context.log("..."),遇见如下错误:Warning:Unexpectedcallto'log'onthecontextobjectafterfunctionexecutionhascompleted.Pleasecheck......
  • CUDA编程 基础与实践 樊哲勇 电子书 pdf
    作者:樊哲勇出版社:清华大学出版社出版年:2020-10 关注公众号:红宸笑。回复:电子书即可  CUDA是目前较为流行的GPU高性能计算的开发工具之一。本书通过大量实例系统地讲述CUDA编程的重要方面。前12章通过一些简短的例子循序渐进地介绍CUDA编程的基础知识,主要包......