zoukankan      html  css  js  c++  java
  • 内存泄露问题分析2

    目前遇到线上内存泄露

    • valgrind 不能用 使用smaps gdb dump  内存后使用string 来分析,目前没有看到结果
    • 使用ltrace 跟踪malloc mmap 等?还是使用systemtap中跟踪 user-process 

    继续分析一下 :

    目前arm 版本 systemtap utrace 貌似不支持;ltrace 只能看到 malloc free 调用,但是看不到调用函数站,不是非常友好

    找一下BCC工具链看有没有现成的,按照以前的理解,BCC工具也是基于kprobe吧

    可以先看下systemp的官方例程中关于malloc的使用跟踪

    #! /usr/bin/env stap
    
    # http://developerblog.redhat.com/2015/01/06/malloc-systemtap-probes-an-example/
    
    
    global sbrk, waits, arenalist, mmap_threshold = 131072, heaplist
      
      
    # sbrk accounting
      
    probe process("/lib*/libc.so.6").mark("memory_sbrk_more")
    {
      sbrk += $arg2
    }
      
    probe process("/lib*/libc.so.6").mark("memory_sbrk_less")
    {
      sbrk -= $arg2
    }
    
    
    # threshold tracking
    
    probe process("/lib*/libc.so.6").mark("memory_mallopt_free_dyn_thresholds")
    {
      printf("%d: New thresholds: mmap: %ld bytes, trim: %ld bytes
    ", tid(), $arg1,
             $arg2)
      mmap_threshold = $arg1
    }
    
    
    # arena accounting
    
    probe process("/lib*/libc.so.6").mark("memory_arena_new")
    {
      printf ("%d: Created new arena
    ", tid())
      arenalist[$arg1, tid()] = 1
    }
    
    probe process("/usr/lib*/libc.so.6").mark("memory_arena_reuse_wait")
    {
      waits[tid()]++
    }
    
    probe process("/usr/lib*/libc.so.6").mark("memory_arena_reuse")
    {
      if ($arg2 != 0)
        {
          printf ("%d: failed to allocate on own arena, trying another
    ", tid())
          arenalist[$arg1, tid()] = 1
        }
    }
    
    probe process("/usr/lib*/libc.so.6").mark("memory_arena_reuse_free_list")
    {
      arenalist[$arg1, tid()] = 1
    }
    
    probe process.thread.end
    {
      /* Find the thread and mark its arena as unused.  */
      %( systemtap_v >= "2.6"
      %?
        delete arenalist[*, tid()]
      %:
        foreach ([a, t] in arenalist)
          if (t == tid())
            break
        delete arenalist[a, t]
      %)
    }
    
    
    # heap accounting
    
    probe process("/usr/lib*/libc.so.6").mark("memory_heap_new")
    {
      printf("%d: New heap
    ", tid());
      heaplist[$arg1] = $arg2
    }
    
    probe process("/usr/lib*/libc.so.6").mark("memory_heap_more")
    {
      heaplist[$arg1] = $arg2
    }
    
    probe process("/usr/lib*/libc.so.6").mark("memory_heap_less")
    {
      heaplist[$arg1] = $arg2
    }
    
    probe process("/usr/lib*/libc.so.6").mark("memory_heap_free")
    {
      delete heaplist[$arg1]
    }
    
    
    # reporting
    
    probe begin
    {
      if (target() == 0) error ("please specify target process with -c / -x")
    }
    
    probe end
    {
      printf ("malloc information for pid %d
    ", target())
      printf ("Contention: 
    ")
      foreach (t in waits)
      printf ("	%d: %d waits
    ", t, waits[t])
      
      print("Active arenas:
    ")
      foreach ([a, t] in arenalist)
      {
        if (arenalist[a, t])
          printf ("	%d -> %p
    ", t, a)
      }
      
      print ("Allocated heaps:
    ")
      foreach (h in heaplist)
      {
        if (heaplist[h])
          printf ("	%p -> %ld bytes
    ", h, heaplist[h])
      }
      
      printf ("Total sbrk: %ld bytes
    ", sbrk)
      printf ("Mmap threshold in the end: %ld kb
    ", mmap_threshold / 1024)
    }
    View Code

    以上代码就不详细分析了

    目前需求是使用一个map记录malloc当前的堆栈,key-->val分别为地址---->堆栈 free的时候,从map中去掉,如果两次free 就会发现map 中没有此数据,此时认为重复释放

    为了便于分析:从arm 平台转为x86吧

    #! /usr/bin/env stap
    global memaddr_tbl
    
    global memaddr_bt_tbl
    
    process("/lib64/libc.so.6").function("__libc_calloc").return {
        if (target() == pid()) {
            if (memaddr_tbl[$return] == 0) {
                memaddr_tbl[$return]++
                memaddr_bt_tbl[$return] = sprint_ubacktrace()
            }
        }
    }
    
    probe process("/lib64/libc.so.6").function("__libc_malloc").return {
        if (target() == pid()) {
            if (memaddr_tbl[$return] == 0) {
                memaddr_tbl[$return]++
                memaddr_bt_tbl[$return] = sprint_ubacktrace()
            }
        }
    }
    
    
    probe process("/lib64/libc.so.6").function("__libc_free").call {
        if (target() == pid()) {
            memaddr_tbl[$mem]--
    
            if (memaddr_tbl[$mem] == 0) {
              //-----------------------
            } else if (memaddr_tbl[$mem] < 0 && $mem != 0) {
                //double free  
                print_ubacktrace()
                
            }
        }
    }
    
    probe end {
        // output memleak
        printf("=============end============
    ")
        foreach(mem in memaddr_tbl) {
            if (memaddr_tbl[mem] > 0) {
                printf("%s
    ", memaddr_bt_tbl[mem])
            }
        }
    }

    以上例程是可以解决用户态内存泄漏点

    但是 arm 平台有点不好处理! 目前虽然arm 和x86平台大部分代码一样,但是还存在部分差异,继续分析 arm差异化代码可能性

    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子
  • 相关阅读:
    Repository中进行模糊查询
    Spring jpa添加查询条件
    java后端repository层中进行模糊查询
    MyBatis小白问题 1、Invalid bound statement (not found): com.itheima.dao.UserDao.findAll,2、Resources.getResourceAsStream()报错
    Date类型做加减运算
    时间格式转换
    mysql-支持的数据类型
    mysql—表的完整性约束
    数据库—表操作(第二章)
    mysql—使用python操作mysql数据库(第五章)
  • 原文地址:https://www.cnblogs.com/codestack/p/15071465.html
Copyright © 2011-2022 走看看