『壹』 linux下一般怎么诊断是哪个进程有memory leak
Memcheck。这是应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。
Callgrind。它主要用来检查程序中函数调用过程中出现的问题。
Cachegrind。它主要用来检查程序中缓存使用出现的问题。
Helgrind。它主要用来检查多线程程序中出现的竞争问题。
Massif。它主要用来检查程序中堆栈使用中出现的问题。
Extension。可以利用core提供的功能,自己编写特定的内存调试工具
用法:valgrind[options] prog-and-args [options]: 常用选项,适用于所有Valgrind工具
-tool=<name> 最常用的选项。运行valgrind中名为toolname的工具。默认memcheck。
h –help 显示帮助信息。
-version 显示valgrind内核的版本,每个工具都有各自的版本。
q –quiet 安静地运行,只打印错误信息。
v –verbose 更详细的信息, 增加错误数统计。
-trace-children=no|yes 跟踪子线程? [no]
-track-fds=no|yes 跟踪打开的文件描述?[no]
-time-stamp=no|yes 增加时间戳到LOG信息? [no]
-log-fd=<number> 输出LOG到描述符文件 [2=stderr]
-log-file=<file> 将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID
-log-file-exactly=<file> 输出LOG信息到 file
-log-file-qualifier=<VAR> 取得环境变量的值来做为输出信息的文件名。 [none]
-log-socket=ipaddr:port 输出LOG到socket ,ipaddr:port
-xml=yes 将信息以xml格式输出,只有memcheck可用
-num-callers=<number> show <number> callers in stack traces [12]
-error-limit=no|yes 如果太多错误,则停止显示新错误? [yes]
-error-exitcode=<number> 如果发现错误则返回错误代码 [0=disable]
-db-attach=no|yes 当出现错误,valgrind会自动启动调试器gdb。[no]
-db-command=<command> 启动调试器的命令行选项[gdb -nw %f %p]
适用于Memcheck工具的相关选项:
-leak-check=no|summary|full 要求对leak给出详细信息? [summary]
-leak-resolution=low|med|high how much bt merging in leak check [low]
-show-reachable=no|yes show reachable blocks in leak check? [no]
下面是一段有问题的C程序代码test.c
#i nclude <stdlib.h>
void f(void)
{
int* x = malloc(10 * sizeof(int));
x[10] = 0; //问题1: 数组下标越界
} //问题2: 内存没有释放
int main(void)
{
f();
return 0;
}
1、 编译程序test.c
gcc -Wall test.c -g -o test
2、 使用Valgrind检查程序BUG
valgrind --tool=memcheck --leak-check=full ./test
使用未初始化内存问题
对于位于程序中不同段的变量,其初始值是不同的,全局变量和静态变量初始值为0,而局部变量和动态申请的变量,其初始值为随机值。如果程序使用了为随机值的变量,那么程序的行为就变得不可预期。
下面的程序就是一种常见的,使用了未初始化的变量的情况。数组a是局部变量,其初始值为随机值,而在初始化时并没有给其所有数组成员初始化,如此在接下来使用这个数组时就潜在有内存问题。
输出结果显示,在该程序的第15行,进行了非法的写操作;在第16行,进行了非法读操作。准确地发现了上述问题
『贰』 static 变量初始化分析
在C++中,静态变量的初始化策略有所不同,特别是全局和局部静态变量。它们均存储在bss段,但初始化方式各异。全局静态变量在程序启动前初始化,确保线程安全;而局部静态变量则在首次调用相关函数时初始化,可能引发多线程并发问题。Linux平台的局部静态变量初始化涉及对一个bss段标记的检查:如果未初始化,会加锁后开始初始化,并更新标记。Windows环境下,初始化逻辑相似,但使用的标志值和初始化条件不同,同样包含二次加锁机制。
在代码层面,我们可以观察到如下的初始化过程:
- Linux:在执行初始化语句时,首先检查一个bss段的标记,若未初始化,进行加锁,初始化后将标记设为已初始化,且可能包含二次加锁以避免并发问题。
- Windows:在同样检查标记值后,Windows环境认为0x80000001表示初始化,与Linux的0x00000001不同。初始化过程同样包含加锁和二次判断。
通过调试工具,如gdb和objmp,可以查看汇编代码,具体到地址的值和操作,从而理解这个初始化机制是如何确保局部静态变量在多线程环境下的线程安全的。
『叁』 Linux动态链接为什么要用PLT和GOT表
编译时,-fPIC编的是.so文件,这个文件也是要访问外部变量的,但是链接它程序很多,它里面的地址不能写死。 以下引用一段话,关键第一句:
对于模块外部引用的全局变量和全局函数,用 GOT表的表项内容作为地址来间接寻址;对于本模块内的静态变量和静态函数,用 GOT表的首地址作为一个基准,用相对于该基准的偏移量来引用,因为不论程序被加载到何种地址空间,模块内的静态变量和静态函数与GOT 的距离是固定的,并且在链接阶段就可知晓其距离的大小。这样,PIC 使用 GOT来引用变量和函数的绝对地址,把位置独立的引用重定向到绝对位置。
『肆』 linux是多线程还是多进程
进程:可执行程序是存储在磁盘设备上的由代码和数据按某种格式组织的静态实体,而内进程是可被容调度的代码的动态运行。在Linux系统中,每个进程都有各自的生命周期。在一个进程的生命周期中,都有各自的运行环境以及所需的资源,这些信息都记录在各自的进程控制块中,以便系统对这些进程进行有效的管理,进程控制块的结构如下图所示:
每个进程都有各自独立的虚拟地址空间,空间的大小与所基于的硬件体系结构有关。虚拟空间中各区代表的意义,代码段存储指令序列和只读数据,多个进程实例可共享代码段。数据段用来存放全局变量和静态变量。堆区域用于程序的动态内存管理,new或者malloc申请的内存就位于堆中。栈用来存放进程运行过程中的局部变量,函数返回地址,参数和进程上下文环境。
线程:引入进程是为了解决程序并发执行的问题,而引入线程是为了减少程序并发所带来的时间和空间的开销,线程是比进程更小的单位,一个进程至少有一个线程,线程是操作系统进行调度的基本单位,线程基本上不占用系统资源,线程与其他同属一个进程的线程共享该进程所占有的资源。
linux是个系统,支持各种服务,服务可以开启多进程,进程可以开启多线程
『伍』 java内存机制的本地方法接口,本地方法栈,static静态数据的问题
虽然 JVM 是来 Java 虚拟的计算机,自同样有堆内存和栈内存。但 Java 程序运行时,供成员变量存储的堆内存,以及供局部变量存储的栈内存,都是由操作系统(如 Windows, Linux等)提供。而 JVM 的堆内存和栈内存,其作用是调用操作系统的内存或文件后进行模拟用的。 其实把JVM看成是个中间层就可以,不止是内存分配,还有线程、网络连接等等,最终在底层都要靠操作系统来搞。
首先内存总体分为了4个部分,包括 stack segment 、heap segment、code segment 、data segment ;
其中我们程序中用关键字new出来的东西都是存放在heap segment;
程序中的局部变量存放在stack segment,这些局部变量是在具体方法执行结束之后,系统自动释放内存资源(而heap segment中的资源需要java垃圾回收机制来处理);
程序中的方法,是内存中的code segment中的,而且是多个对象 共享一个代码空间区域;
static静态变量,需要放在内存中的data segment中,
『陆』 linux系统中 初始化的全局变量和未初始化过的全局变量保存在哪
一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动回分配释放 ,存放函答数的参数值,局部变量的值等。其
操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另
一块区域。 - 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
『柒』 linux下怎样使用自己创建的一个静态库: 这个静态库中有一个全局变量和函数,会在库外被调用,怎样实现
先编译源代码生成这个静态库,如:libmyfunc.a,存放目录为:./lib
在编译执行码时,增加以下参数:-L./lib -lmyfunc