Linux下c++程序内存泄漏检测代码范例
2023-09-27 14:23:40 时间
Linux下对于程序内存泄漏检测的方法很多,最常用的的莫过于使用valgrind工具。但是valgrind相当于让程序在虚拟机中运行,会带
来较大的系统资源开销,还会对程序的运行效率产生较大影响,对于那种资源占用大的程序,如果需要长时间运行才能暴露的泄漏问题,它就显得不太好用。
std::map void*, _PtrInfo gPtrInfo ; std::map const LmCallStack*, _AllocInfo , __comp gLeakInfo; const int LmCallStack:: MAX_STACK_LAYERS = 32; /* Prototypes for our hooks. */ static void my_init_hook ( void); static void *my_malloc_hook ( size_t, const void *); static void my_free_hook ( void*, const void *); void *(*__MALLOC_HOOK_VOLATILE old_malloc_hook)( size_t __size , const void *) ; void (*__MALLOC_HOOK_VOLATILE old_free_hook) ( void *__ptr , const void *); /* Override initializing hook from the C library. */ void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) ( void) = my_init_hook; void my_init_hook (void) old_malloc_hook = __malloc_hook ; old_free_hook = __free_hook ; __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; static void *my_malloc_hook ( size_t size , const void *caller ) void *result ; gLock.lock (); /* Restore all old hooks */ __malloc_hook = old_malloc_hook ; __free_hook = old_free_hook ; /* Call recursively */ result = malloc (size); /* Save underlying hooks */ old_malloc_hook = __malloc_hook ; old_free_hook = __free_hook ; /* printf might call malloc, so protect it too. */ //printf ("malloc (%u) returns %p\n", (unsigned int) size, result); RecordPtr( result , size); /* Restore our own hooks */ __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; gLock.unlock (); return result ; static void my_free_hook ( void *ptr , const void *caller ) gLock.lock (); /* Restore all old hooks */ __malloc_hook = old_malloc_hook ; __free_hook = old_free_hook ; /* Call recursively */ free (ptr ); /* Save underlying hooks */ old_malloc_hook = __malloc_hook ; old_free_hook = __free_hook ; /* printf might call free, so protect it too. */ //printf ("freed pointer %p\n", ptr); RemovePtr( ptr ); /* Restore our own hooks */ __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; gLock.unlock (); void RecordPtr ( void* ptr, size_t size) // 获取调用栈 void *array [LmCallStack:: MAX_STACK_LAYERS]; int cstSize = backtrace( array, LmCallStack ::MAX_STACK_LAYERS); // 保存指针 调用栈 LmCallStack* callstack = new LmCallStack(array , cstSize); gLock.lock (); std::map const LmCallStack*, _AllocInfo , __comp :: iterator it = gLeakInfo.find (callstack); if (it != gLeakInfo. end()) { it- second .size += size; it- second .alloc++; _PtrInfo pi (it- first, size ); gPtrInfo[ptr ] = pi; } else { _AllocInfo aif (size, 1, 0); std::pair std:: map const LmCallStack*, _AllocInfo, __comp ::iterator , bool ret = gLeakInfo .insert( std::pair const LmCallStack*, _AllocInfo (callstack, aif)); if (ret .second) { _PtrInfo pi (ret. first- first , size); gPtrInfo[ptr ] = pi; } else { // failed } } gLock.unlock (); void RemovePtr ( void* ptr ) gLock.lock (); std::map void*, _PtrInfo ::iterator it = gPtrInfo.find (ptr); if (it != gPtrInfo. end()) { std::map const LmCallStack*, _AllocInfo , __comp :: iterator itc = gLeakInfo .find( it- second .csk); if (itc != gLeakInfo. end()) { itc- second .size -= it- second .size; itc- second .free++; if (0 == (itc - second. alloc - itc - second. free)) { assert(0 == itc - second. size); delete itc - first; gLeakInfo.erase (itc); } } gPtrInfo.erase (it); } gLock.unlock (); void Report () char **strings = NULL; gLock.lock (); __malloc_hook = old_malloc_hook ; __free_hook = old_free_hook ; for (std ::map const LmCallStack *, _AllocInfo, __comp ::iterator it = gLeakInfo .begin(); it != gLeakInfo .end(); it++) { printf("\n" ); printf("==== size: %ld, allocs: %d, frees: %d, a-f: %d\n", it- second.size , it- second.alloc , it- second.free , it- second .alloc- it- second .free ); printf("==== stacks back trace:\n" ); strings = backtrace_symbols ((void**) it- first - callstack, it- first - size); if (strings ) { for(int i = 2; i it - first- size; i ++) { //printf(" %s\n", strings[i]); char output [1024] = {0}; memset(output , 0, 1024); char temp [1024] = {0}; memset(temp , 0, 1024); //// //// get real function name //// if (1 == sscanf (strings[ i], "%*[^(]%*[^_]%[^)+]" , temp)) { int status ; char* realname = abi::__cxa_demangle (temp, 0, 0, status); if (0 == status ) { char* p = strchr( strings[i ], (); memcpy(output , strings[ i], p-strings [i]); sprintf(output +(p- strings[i ]), "(%s+%p) " , realname, (( void**)it - first- callstack)[i ]); //printf(" -%s\n", realname); free(realname ); } else { char* p = strchr( strings[i ], )); memcpy(output , strings[ i], p-strings [i]+2); } } else { char* p = strchr( strings[i ], )); memcpy(output , strings[ i], p-strings [i]+2); } FILE * fp ; char module [1024] = {0}; memset(module , 0, 1024); char* pm = strchr( strings[i ], (); memcpy(module , strings[ i], pm -strings[ i]); if (strstr (module, ".so")) { __pid_t pid = getpid(); sprintf(temp , "grep %s /proc/%d/maps", module, pid ); /// /// get library base-map-address /// fp = popen (temp, "r"); if (fp ) { char baseaddr [64]; unsigned long long base; fgets(temp , sizeof( temp)-1, fp ); //printf("memmap: %s\n", temp); sscanf(temp , "%[^-]", baseaddr); base = strtoll (baseaddr, NULL, 16); //printf("baseaddr:%s\n", baseaddr); //printf(" base:0x%llx\n", base); sprintf(temp , "addr2line -e %s %p", module, (void *)((unsigned long long)((void **)it- first- callstack )[i]- base)); } } else { sprintf(temp , "addr2line -e %s %p", module, ((void **)it- first- callstack )[i]); } //// //// get source file name and line number //// fp = popen (temp, "r"); //printf("cmdline: %s\n", temp); if (fp ) { fgets(temp , sizeof( temp)-1, fp ); //printf(" -%s\n", temp); strcat(output , temp); printf(" - %s" , output); pclose(fp ); } else { printf(" - %s\n" , output); } } free(strings ); strings = NULL ; } } __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; gLock.unlock (); ////////////////////////////////////////////////////////////////////////// CMutexLock::CMutexLock () pthread_mutexattr_t m_attr ; pthread_mutexattr_init( m_attr ); pthread_mutexattr_settype( m_attr , PTHREAD_MUTEX_RECURSIVE); if (0 != pthread_mutex_init ( m_mutex , m_attr)) { printf("c_lock::c_lock pthread_mutex_init error %d .\n" , errno); assert(0); } pthread_mutexattr_destroy( m_attr ); CMutexLock::~CMutexLock () if(0 != pthread_mutex_destroy ( m_mutex)) { printf("c_lock::~c_lock pthread_mutex_destroy error %d .\n" , errno); assert(0); } void CMutexLock::lock () if(0 != pthread_mutex_lock ( m_mutex)) { assert("c_lock::lock pthread_mutex_lock " 0); } void CMutexLock::unlock () int iRet = 0; if(0 != (iRet = pthread_mutex_unlock( m_mutex))) { printf("c_lock::unlock pthread_mutex_unlock ret %d error %d .\n", iRet, errno ); assert(0); } 示例代码: leakmom.h //////////////////////////////////////////////////////////////////////// // The Executable file MUST be linked with parameter -rdynamic !!! //////////////////////////////////////////////////////////////////////// #pragma once #include string.h #include pthread.h class LmCallStack public: char* callstack ; // pointer to buffer recording callstack addresses int size ; // count of call stacks static const int MAX_STACK_LAYERS; public: LmCallStack(void * csk= NULL, int s=0) { if (csk ) { callstack = new char[ s*sizeof (void*)]; memcpy(callstack , csk, s*sizeof (void*)); } else { callstack = (char *)csk; } size = s ; } ~ LmCallStack() { if (callstack ) { delete[] callstack ; } callstack = NULL ; size = 0; } class __comp public: __comp(){}; bool operator () (const LmCallStack* first , const LmCallStack* second) { return ((first - size second- size ) || ( first- size == second- size memcmp(first - callstack, second- callstack , sizeof( void*)*first - size) 0) ); } struct _PtrInfo _PtrInfo(const LmCallStack* c=NULL , long s=0) { csk = c ; size = s ; } const LmCallStack * csk; long size ; struct _AllocInfo _AllocInfo(long s=0, int a =0, int f=0) { size=s ; alloc=a ; free=f ; } // long size ; int alloc ; int free ; class CMutexLock public: CMutexLock(); ~ CMutexLock(); public: void lock (); void unlock (); private: pthread_mutex_t m_mutex ; void RecordPtr ( void* ptr, size_t size); void RemovePtr (void* ptr); void Report ();
Android C++系列:Linux Socket编程(四)多路IO转接服务器 select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开 的文件描述符个数并不能改变select监听文件个数
Android C++ 系列:Linux Socket 编程(三)CS 模型示例 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于 监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服 务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK 段,服务器收到后从accept()返回。
Android C++ 系列:Linux Socket 编程(二)网络套接字函数 socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描 述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调 用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为 SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表 示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。
Android C++ 系列:Linux Socket 编程(一)预备知识 为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运 行,可以调用以下库函数做网络字节序和主机字节序的转换。
Android C++ 系列:Linux 常用函数和工具 如果times是非空指针,则存取时间和修改时间被设置为 times所指向的结构中的值。此 时,进程的有效用户ID必须等于该文件的所有者 ID,或者进程必须是一个超级用户进程。对 文件只具有写许可权是不够的
Android C++系列:Linux信号(三) 例如:strtok就是一个不可重入函数,因为strtok内部维护了一个内部静态指针,保存上一 次切割到的位置,如果信号的捕捉函数中也去调用strtok函数,则会造成切割字符串混乱, 应用strtok_r版本,r表示可重入。
Android C++系列:Linux信号(二) 如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非 空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针, 则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前 的信号屏蔽字为mask,下表说明了how参数的可选值。
Android C++系列:Linux进程间通信(二) mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存 地址,对文件的读写可以直接用指针来做而不需要read/write函数。
Android C++系列:Linux进程间通信(一) 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不 到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用 户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程 间通信(IPC,InterProcess Communication)。
linux下的c++程序中自己实现一个轻量级的泄漏检测代码其实是比较方便的,下面我就给出一个简单的范例,并作简单的说明。当然,我们还是应该提倡使用共享指针,用共享指针自动管理内存可以避免内存泄漏这样的不必要的麻烦。
进一步处理:
使用abi::__cxa_demangle把函数名解析为源代码风格; 使用addr2line解析出函数调用栈对应的代码行; 对于动态库(.so)中的地址解析,需要先在/proc/ pid /maps文件中找到动态库映射的基地址,才能做解析。注意:
编译连接参数中使用-g -rdynamic
以上每步具体实现的代码可能都没有达到最优,甚至可能是笨办法,如果有更好的实现方案请直接替换,也欢迎赐教。
示例代码: leakmom.cppstd::map void*, _PtrInfo gPtrInfo ; std::map const LmCallStack*, _AllocInfo , __comp gLeakInfo; const int LmCallStack:: MAX_STACK_LAYERS = 32; /* Prototypes for our hooks. */ static void my_init_hook ( void); static void *my_malloc_hook ( size_t, const void *); static void my_free_hook ( void*, const void *); void *(*__MALLOC_HOOK_VOLATILE old_malloc_hook)( size_t __size , const void *) ; void (*__MALLOC_HOOK_VOLATILE old_free_hook) ( void *__ptr , const void *); /* Override initializing hook from the C library. */ void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) ( void) = my_init_hook; void my_init_hook (void) old_malloc_hook = __malloc_hook ; old_free_hook = __free_hook ; __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; static void *my_malloc_hook ( size_t size , const void *caller ) void *result ; gLock.lock (); /* Restore all old hooks */ __malloc_hook = old_malloc_hook ; __free_hook = old_free_hook ; /* Call recursively */ result = malloc (size); /* Save underlying hooks */ old_malloc_hook = __malloc_hook ; old_free_hook = __free_hook ; /* printf might call malloc, so protect it too. */ //printf ("malloc (%u) returns %p\n", (unsigned int) size, result); RecordPtr( result , size); /* Restore our own hooks */ __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; gLock.unlock (); return result ; static void my_free_hook ( void *ptr , const void *caller ) gLock.lock (); /* Restore all old hooks */ __malloc_hook = old_malloc_hook ; __free_hook = old_free_hook ; /* Call recursively */ free (ptr ); /* Save underlying hooks */ old_malloc_hook = __malloc_hook ; old_free_hook = __free_hook ; /* printf might call free, so protect it too. */ //printf ("freed pointer %p\n", ptr); RemovePtr( ptr ); /* Restore our own hooks */ __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; gLock.unlock (); void RecordPtr ( void* ptr, size_t size) // 获取调用栈 void *array [LmCallStack:: MAX_STACK_LAYERS]; int cstSize = backtrace( array, LmCallStack ::MAX_STACK_LAYERS); // 保存指针 调用栈 LmCallStack* callstack = new LmCallStack(array , cstSize); gLock.lock (); std::map const LmCallStack*, _AllocInfo , __comp :: iterator it = gLeakInfo.find (callstack); if (it != gLeakInfo. end()) { it- second .size += size; it- second .alloc++; _PtrInfo pi (it- first, size ); gPtrInfo[ptr ] = pi; } else { _AllocInfo aif (size, 1, 0); std::pair std:: map const LmCallStack*, _AllocInfo, __comp ::iterator , bool ret = gLeakInfo .insert( std::pair const LmCallStack*, _AllocInfo (callstack, aif)); if (ret .second) { _PtrInfo pi (ret. first- first , size); gPtrInfo[ptr ] = pi; } else { // failed } } gLock.unlock (); void RemovePtr ( void* ptr ) gLock.lock (); std::map void*, _PtrInfo ::iterator it = gPtrInfo.find (ptr); if (it != gPtrInfo. end()) { std::map const LmCallStack*, _AllocInfo , __comp :: iterator itc = gLeakInfo .find( it- second .csk); if (itc != gLeakInfo. end()) { itc- second .size -= it- second .size; itc- second .free++; if (0 == (itc - second. alloc - itc - second. free)) { assert(0 == itc - second. size); delete itc - first; gLeakInfo.erase (itc); } } gPtrInfo.erase (it); } gLock.unlock (); void Report () char **strings = NULL; gLock.lock (); __malloc_hook = old_malloc_hook ; __free_hook = old_free_hook ; for (std ::map const LmCallStack *, _AllocInfo, __comp ::iterator it = gLeakInfo .begin(); it != gLeakInfo .end(); it++) { printf("\n" ); printf("==== size: %ld, allocs: %d, frees: %d, a-f: %d\n", it- second.size , it- second.alloc , it- second.free , it- second .alloc- it- second .free ); printf("==== stacks back trace:\n" ); strings = backtrace_symbols ((void**) it- first - callstack, it- first - size); if (strings ) { for(int i = 2; i it - first- size; i ++) { //printf(" %s\n", strings[i]); char output [1024] = {0}; memset(output , 0, 1024); char temp [1024] = {0}; memset(temp , 0, 1024); //// //// get real function name //// if (1 == sscanf (strings[ i], "%*[^(]%*[^_]%[^)+]" , temp)) { int status ; char* realname = abi::__cxa_demangle (temp, 0, 0, status); if (0 == status ) { char* p = strchr( strings[i ], (); memcpy(output , strings[ i], p-strings [i]); sprintf(output +(p- strings[i ]), "(%s+%p) " , realname, (( void**)it - first- callstack)[i ]); //printf(" -%s\n", realname); free(realname ); } else { char* p = strchr( strings[i ], )); memcpy(output , strings[ i], p-strings [i]+2); } } else { char* p = strchr( strings[i ], )); memcpy(output , strings[ i], p-strings [i]+2); } FILE * fp ; char module [1024] = {0}; memset(module , 0, 1024); char* pm = strchr( strings[i ], (); memcpy(module , strings[ i], pm -strings[ i]); if (strstr (module, ".so")) { __pid_t pid = getpid(); sprintf(temp , "grep %s /proc/%d/maps", module, pid ); /// /// get library base-map-address /// fp = popen (temp, "r"); if (fp ) { char baseaddr [64]; unsigned long long base; fgets(temp , sizeof( temp)-1, fp ); //printf("memmap: %s\n", temp); sscanf(temp , "%[^-]", baseaddr); base = strtoll (baseaddr, NULL, 16); //printf("baseaddr:%s\n", baseaddr); //printf(" base:0x%llx\n", base); sprintf(temp , "addr2line -e %s %p", module, (void *)((unsigned long long)((void **)it- first- callstack )[i]- base)); } } else { sprintf(temp , "addr2line -e %s %p", module, ((void **)it- first- callstack )[i]); } //// //// get source file name and line number //// fp = popen (temp, "r"); //printf("cmdline: %s\n", temp); if (fp ) { fgets(temp , sizeof( temp)-1, fp ); //printf(" -%s\n", temp); strcat(output , temp); printf(" - %s" , output); pclose(fp ); } else { printf(" - %s\n" , output); } } free(strings ); strings = NULL ; } } __malloc_hook = my_malloc_hook ; __free_hook = my_free_hook ; gLock.unlock (); ////////////////////////////////////////////////////////////////////////// CMutexLock::CMutexLock () pthread_mutexattr_t m_attr ; pthread_mutexattr_init( m_attr ); pthread_mutexattr_settype( m_attr , PTHREAD_MUTEX_RECURSIVE); if (0 != pthread_mutex_init ( m_mutex , m_attr)) { printf("c_lock::c_lock pthread_mutex_init error %d .\n" , errno); assert(0); } pthread_mutexattr_destroy( m_attr ); CMutexLock::~CMutexLock () if(0 != pthread_mutex_destroy ( m_mutex)) { printf("c_lock::~c_lock pthread_mutex_destroy error %d .\n" , errno); assert(0); } void CMutexLock::lock () if(0 != pthread_mutex_lock ( m_mutex)) { assert("c_lock::lock pthread_mutex_lock " 0); } void CMutexLock::unlock () int iRet = 0; if(0 != (iRet = pthread_mutex_unlock( m_mutex))) { printf("c_lock::unlock pthread_mutex_unlock ret %d error %d .\n", iRet, errno ); assert(0); } 示例代码: leakmom.h //////////////////////////////////////////////////////////////////////// // The Executable file MUST be linked with parameter -rdynamic !!! //////////////////////////////////////////////////////////////////////// #pragma once #include string.h #include pthread.h class LmCallStack public: char* callstack ; // pointer to buffer recording callstack addresses int size ; // count of call stacks static const int MAX_STACK_LAYERS; public: LmCallStack(void * csk= NULL, int s=0) { if (csk ) { callstack = new char[ s*sizeof (void*)]; memcpy(callstack , csk, s*sizeof (void*)); } else { callstack = (char *)csk; } size = s ; } ~ LmCallStack() { if (callstack ) { delete[] callstack ; } callstack = NULL ; size = 0; } class __comp public: __comp(){}; bool operator () (const LmCallStack* first , const LmCallStack* second) { return ((first - size second- size ) || ( first- size == second- size memcmp(first - callstack, second- callstack , sizeof( void*)*first - size) 0) ); } struct _PtrInfo _PtrInfo(const LmCallStack* c=NULL , long s=0) { csk = c ; size = s ; } const LmCallStack * csk; long size ; struct _AllocInfo _AllocInfo(long s=0, int a =0, int f=0) { size=s ; alloc=a ; free=f ; } // long size ; int alloc ; int free ; class CMutexLock public: CMutexLock(); ~ CMutexLock(); public: void lock (); void unlock (); private: pthread_mutex_t m_mutex ; void RecordPtr ( void* ptr, size_t size); void RemovePtr (void* ptr); void Report ();
Android C++系列:Linux Socket编程(四)多路IO转接服务器 select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开 的文件描述符个数并不能改变select监听文件个数
Android C++ 系列:Linux Socket 编程(三)CS 模型示例 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于 监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服 务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK 段,服务器收到后从accept()返回。
Android C++ 系列:Linux Socket 编程(二)网络套接字函数 socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描 述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调 用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为 SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表 示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。
Android C++ 系列:Linux Socket 编程(一)预备知识 为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运 行,可以调用以下库函数做网络字节序和主机字节序的转换。
Android C++ 系列:Linux 常用函数和工具 如果times是非空指针,则存取时间和修改时间被设置为 times所指向的结构中的值。此 时,进程的有效用户ID必须等于该文件的所有者 ID,或者进程必须是一个超级用户进程。对 文件只具有写许可权是不够的
Android C++系列:Linux信号(三) 例如:strtok就是一个不可重入函数,因为strtok内部维护了一个内部静态指针,保存上一 次切割到的位置,如果信号的捕捉函数中也去调用strtok函数,则会造成切割字符串混乱, 应用strtok_r版本,r表示可重入。
Android C++系列:Linux信号(二) 如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非 空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针, 则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前 的信号屏蔽字为mask,下表说明了how参数的可选值。
Android C++系列:Linux进程间通信(二) mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存 地址,对文件的读写可以直接用指针来做而不需要read/write函数。
Android C++系列:Linux进程间通信(一) 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不 到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用 户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程 间通信(IPC,InterProcess Communication)。
相关文章
- linux c++ 服务器端开发面试必看书籍
- Linux chroot命令函数介绍(C/C++)
- linux 进程监控
- Linux 中流行的邮件传输代理
- Linux有问必答:如何在curl中设置自定义的HTTP头
- linux内核是在哪里创建1号进程的?
- 【转】Linux 上的最佳 C/C++ IDE
- linux环境下查看C/C++程序的堆栈信息
- C++ Linux Window
- 《嵌入式Linux基础教程(第2版)》——1.2 嵌入式Linux现状
- linux ioctl 接口
- linux Completions 机制
- Exit- Linux必学的60个命令
- linux VFS 之一 :虚拟文件系统的面向对象设计思想
- Linux环境下配置vscode的C/C++ 的make编译环境(编写makefile方式)代码Demo版
- linux下C++修改文件内容
- linux下使用C++ Json库
- Linux系统下C/C++开发mysql数据库应用
- Linux C/C++ ------ “” and <> in the use of head include file(Pending Verification)
- 【正点原子Linux连载】 第十九章 CAN Bus 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2
- linux下配置LAMP开发环境,以及经常使用小细节
- Linux的动态定时器-时间轮
- linux 下Eclipse for C/C++的不常见设置
- Linux C/C++方向开发(13周学习路线)
- linux下快速打包/多线程压缩文件的方法
- C/C++教程 第二十五章 —— Linux系统入门
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---13
- Linux下使用valgrind工具对C++编程检测内存泄露