⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1161.html

📁 著名的linux英雄站点的文档打包
💻 HTML
📖 第 1 页 / 共 5 页
字号:
int main(void)<br>
{<br>
  char *ptr1;<br>
  char *ptr2;<br>
<br>
  ptr1 = malloc(512);<br>
  ptr2 = malloc(512);<br>
<br>
  ptr2 = ptr1;<br>
  free(ptr2);<br>
  free(ptr1);<br>
}[/code:1:ff78191c7b]<br>
清单 1 中的代码将分配两个 512 字节的内存块,然后指向第一个内存块的指针被设定为指向第二个内存块。结果,第二个内存块的地址丢失,从而产生了内存泄漏。<br>
现在我们编译清单 1 的 memwatch.c。下面是一个 makefile 示例:<br>
test1 <br>
<br>
[code:1:ff78191c7b]gcc -DMEMWATCH -DMW_STDIO test1.c memwatch c -o test1[/code:1:ff78191c7b]<br>
当您运行 test1 程序后,它会生成一个关于泄漏的内存的报告。清单 2 展示了示例 memwatch.log 输出文件。<br>
清单 2. test1 memwatch.log 文件 <br>
<br>
[code:1:ff78191c7b]MEMWATCH 2.67 Copyright (C) 1992-1999 Johan Lindh<br>
<br>
...<br>
double-free: &lt;4&gt; test1.c(15), 0x80517b4 was freed from test1.c(14)<br>
...<br>
unfreed: &lt;2&gt; test1.c(11), 512 bytes at 0x80519e4<br>
{FE FE FE FE FE FE FE FE FE FE FE FE ..............}<br>
<br>
Memory usage statistics (global):<br>
  N)umber of allocations made:  2<br>
  L)argest memory usage :  1024<br>
  T)otal of all alloc() calls:  1024<br>
  U)nfreed bytes totals :  512[/code:1:ff78191c7b]<br>
MEMWATCH 为您显示真正导致问题的行。如果您释放一个已经释放过的指针,它会告诉您。对于没有释放的内存也一样。日志结尾部分显示统计信息,包括泄漏了多少内存,使用了多少内存,以及总共分配了多少内存。<br>
[color=blue:ff78191c7b]YAMD[/color:ff78191c7b]<br>
YAMD 软件包由 Nate Eldredge 编写,可以查找 C 和 C++ 中动态的、与内存分配有关的问题。在撰写本文时,YAMD  的最新版本为 0.32。请下载 yamd-0.32.tar.gz(请参阅参考资料)。执行 make 命令来构建程序;然后执行  make install 命令安装程序并设置工具。<br>
一旦您下载了 YAMD 之后,请在 test1.c 上使用它。请删除 #include memwatch.h 并对 makefile 进行如下小小的修改:<br>
使用 YAMD 的 test1 <br>
<br>
gcc -g test1.c -o test1<br>
清单 3 展示了来自 test1 上的 YAMD 的输出。<br>
清单 3. 使用 YAMD 的 test1 输出 <br>
<br>
[code:1:ff78191c7b]YAMD version 0.32<br>
Executable: /usr/src/test/yamd-0.32/test1<br>
...<br>
INFO: Normal allocation of this block<br>
Address 0x40025e00, size 512<br>
...<br>
INFO: Normal allocation of this block<br>
Address 0x40028e00, size 512<br>
...<br>
INFO: Normal deallocation of this block<br>
Address 0x40025e00, size 512<br>
...<br>
ERROR: Multiple freeing At<br>
free of pointer already freed<br>
Address 0x40025e00, size 512<br>
...<br>
WARNING: Memory leak<br>
Address 0x40028e00, size 512<br>
WARNING: Total memory leaks:<br>
1 unfreed allocations totaling 512 bytes<br>
<br>
*** Finished at Tue ... 10:07:15 2002<br>
Allocated a grand total of 1024 bytes 2 allocations<br>
Average of 512 bytes per allocation<br>
Max bytes allocated at one time: 1024<br>
24 K alloced internally / 12 K mapped now / 8 K max<br>
Virtual program size is 1416 K<br>
End.[/code:1:ff78191c7b]<br>
YAMD 显示我们已经释放了内存,而且存在内存泄漏。让我们在清单 4 中另一个样本程序上试试 YAMD。<br>
清单 4. 内存代码(test2.c) <br>
<br>
[code:1:ff78191c7b]#include &lt;stdlib.h&gt;<br>
#include &lt;stdio.h&gt;<br>
<br>
int main(void)<br>
{<br>
  char *ptr1;<br>
  char *ptr2;<br>
  char *chptr;<br>
  int i = 1;<br>
  ptr1 = malloc(512);<br>
  ptr2 = malloc(512);<br>
  chptr = (char *)malloc(512);<br>
  for (i; i &lt;= 512; i++) {<br>
    chptr[i] = 'S';<br>
  }<br>
  ptr2 = ptr1;<br>
  free(ptr2);<br>
  free(ptr1);<br>
  free(chptr);<br>
}[/code:1:ff78191c7b]<br>
您可以使用下面的命令来启动 YAMD:<br>
[code:1:ff78191c7b]./run-yamd /usr/src/test/test2/test2 [/code:1:ff78191c7b]<br>
清单 5 显示了在样本程序 test2 上使用 YAMD 得到的输出。YAMD 告诉我们在 for 循环中有“越界(out-of-bounds)”的情况。<br>
清单 5. 使用 YAMD 的 test2 输出 <br>
<br>
[code:1:ff78191c7b]Running /usr/src/test/test2/test2<br>
Temp output to /tmp/yamd-out.1243<br>
*********<br>
./run-yamd: line 101: 1248 Segmentation fault (core dumped)<br>
YAMD version 0.32<br>
Starting run: /usr/src/test/test2/test2<br>
Executable: /usr/src/test/test2/test2<br>
Virtual program size is 1380 K<br>
...<br>
INFO: Normal allocation of this block<br>
Address 0x40025e00, size 512<br>
...<br>
INFO: Normal allocation of this block<br>
Address 0x40028e00, size 512<br>
...<br>
INFO: Normal allocation of this block<br>
Address 0x4002be00, size 512<br>
ERROR: Crash<br>
...<br>
Tried to write address 0x4002c000<br>
Seems to be part of this block:<br>
Address 0x4002be00, size 512<br>
...<br>
Address in question is at offset 512 (out of bounds)<br>
Will dump core after checking heap.<br>
Done.[/code:1:ff78191c7b]<br>
MEMWATCH 和 YAMD 都是很有用的调试工具,它们的使用方法有所不同。对于 MEMWATCH,您需要添加包含文件 memwatch.h 并打开两个编译时间标记。对于链接(link)语句,YAMD 只需要 -g 选项。<br>
[color=blue:ff78191c7b]Electric Fence[/color:ff78191c7b]<br>
多数 Linux 分发版包含一个 Electric Fence 包,不过您也可以选择下载它。Electric Fence 是一个由  Bruce Perens 编写的 malloc() 调试库。它就在您分配内存后分配受保护的内存。如果存在 fencepost 错误(超过数组末尾运行),程序就会产生保护错误,并立即结束。通过结合 Electric Fence 和 gdb,您可以精确地跟踪到哪一行试图访问受保护内存。 Electric Fence 的另一个功能就是能够检测内存泄漏。<br>
<br>
 zhchhui 回复于:2003-09-15 10:49:18<br>
[b:95b8e28830] [size=18:95b8e28830]第 2 种情况:使用 strace[/size:95b8e28830][/b:95b8e28830]<br>
strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用。strace 显示这些调用的参数并返回符号形式的值。 strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。将跟踪信息发送到应用程序及内核开发者都很有用。在清单 6 中,分区的一种格式有错误,清单显示了 strace 的开头部分,内容是关于调出创建文件系统操作(mkfs)的。strace 确定哪个调用导致问题出现。<br>
清单 6. mkfs 上 strace 的开头部分 <br>
<br>
[code:1:95b8e28830]execve("/sbin/mkfs.jfs", ["mkfs.jfs", "-f", "/dev/test1"], &<br>
 ...<br>
 open("/dev/test1", O_RDWR|O_LARGEFILE) = 4<br>
 stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0<br>
 ioctl(4, 0x40041271, 0xbfffe128) = -1 EINVAL (Invalid argument)<br>
 write(2, "mkfs.jfs: warning - cannot setb" ..., 98mkfs.jfs: warning -<br>
 cannot set blocksize on block device /dev/test1: Invalid argument )<br>
  = 98<br>
 stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0<br>
 open("/dev/test1", O_RDONLY|O_LARGEFILE) = 5<br>
 ioctl(5, 0x80041272, 0xbfffe124) = -1 EINVAL (Invalid argument)<br>
 write(2, "mkfs.jfs: can't determine device"..., ..._exit(1)<br>
  = ?[/code:1:95b8e28830]<br>
清单 6 显示 ioctl 调用导致用来格式化分区的 mkfs 程序失败。ioctl BLKGETSIZE64 失败。(BLKGET- SIZE64 在调用 ioctl 的源代码中定义。) BLKGETSIZE64 ioctl 将被添加到 Linux 中所有的设备,而在这里,逻辑卷管理器还不支持它。因此,如果 BLKGETSIZE64 ioctl 调用失败,mkfs 代码将改为调用较早的 ioctl 调用;这使得  mkfs 适用于逻辑卷管理器。<br>
<br>
 zhchhui 回复于:2003-09-15 10:57:11<br>
[b:627becdd94][size=18:627becdd94] 第 3 种情况:使用 gdb 和 Oops[/size:627becdd94][/b:627becdd94]<br>
您可以从命令行使用 gdb 程序(Free Software Foundation 的调试器)来找出错误,也可以从诸如  Data Display Debugger(DDD)这样的几个图形工具之一使用 gdb 程序来找出错误。您可以使用 gdb 来调试用户空间程序或 Linux 内核。这一部分只讨论从命令行运行 gdb 的情况。<br>
使用 gdb program name 命令启动 gdb。gdb 将载入可执行程序符号并显示输入提示符,让您可以开始使用调试器。您可以通过三种方式用 gdb 查看进程:<br>
?使用 attach 命令开始查看一个已经运行的进程;attach 将停止进程。<br>
?使用 run 命令执行程序并从头开始调试程序。<br>
?查看已有的核心文件来确定进程终止时的状态。要查看核心文件,请用下面的命令启动 gdb。 <br>
gdb programname corefilename <br>
要用核心文件进行调试,您不仅需要程序的可执行文件和源文件,还需要核心文件本身。要用核心文件启动 gdb,请使用 -c 选项: <br>
gdb -c core programname <br>
gdb 显示哪行代码导致程序发生核心转储。<br>
在运行程序或连接到已经运行的程序之前,请列出您觉得有错误的源代码,设置断点,然后开始调试程序。您可以使用 help 命令查看全面的 gdb 在线帮助和详细的教程。<br>
[color=blue:627becdd94]kgdb[/color:627becdd94]<br>
kgdb 程序(使用 gdb 的远程主机 Linux 内核调试器)提供了一种使用 gdb 调试 Linux 内核的机制。kgdb 程序是内核的扩展,它让您能够在远程主机上运行 gdb 时连接到运行用 kgdb 扩展的内核机器。您可以接着深入到内核中、设置断点、检查数据并进行其它操作(类似于您在应用程序上使用 gdb 的方式)。这个补丁的主要特点之一就是运行 gdb 的主机在引导过程中连接到目标机器(运行要被调试的内核)。这让您能够尽早开始调试。请注意,补丁为 Linux 内核添加了功能,所以 gdb 可以用来调试 Linux 内核。<br>
使用 kgdb 需要两台机器:一台是开发机器,另一台是测试机器。一条串行线(空调制解调器电缆)将通过机器的串口连接它们。您希望调试的内核在测试机器上运行;gdb 在开发机器上运行。gdb 使用串行线与您要调试的内核通信。<br>
请遵循下面的步骤来设置 kgdb 调试环境:<br>
1.下载您的 Linux 内核版本适用的补丁。<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -