MemoryLeakTrackUtil.cpp revision 80a5d305a8408651fbc9b11e9d21125887da8c40
1/* 2 * Copyright 2011, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <media/MemoryLeakTrackUtil.h> 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <sys/types.h> 22#include <unistd.h> 23 24/* 25 * The code here originally resided in MediaPlayerService.cpp and was 26 * shamelessly copied over to support memory leak tracking from 27 * multiple places. 28 */ 29namespace android { 30 31#if defined(__arm__) 32 33extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, 34 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); 35 36extern "C" void free_malloc_leak_info(uint8_t* info); 37 38// Use the String-class below instead of String8 to allocate all memory 39// beforehand and not reenter the heap while we are examining it... 40struct MyString8 { 41 static const size_t MAX_SIZE = 256 * 1024; 42 43 MyString8() 44 : mPtr((char *)malloc(MAX_SIZE)) { 45 *mPtr = '\0'; 46 } 47 48 ~MyString8() { 49 free(mPtr); 50 } 51 52 void append(const char *s) { 53 strncat(mPtr, s, MAX_SIZE - size() - 1); 54 } 55 56 const char *string() const { 57 return mPtr; 58 } 59 60 size_t size() const { 61 return strlen(mPtr); 62 } 63 64 void clear() { 65 *mPtr = '\0'; 66 } 67 68private: 69 char *mPtr; 70 71 MyString8(const MyString8 &); 72 MyString8 &operator=(const MyString8 &); 73}; 74 75void dumpMemoryAddresses(int fd) 76{ 77 const size_t SIZE = 256; 78 char buffer[SIZE]; 79 MyString8 result; 80 81 typedef struct { 82 size_t size; 83 size_t dups; 84 intptr_t * backtrace; 85 } AllocEntry; 86 87 uint8_t *info = NULL; 88 size_t overallSize = 0; 89 size_t infoSize = 0; 90 size_t totalMemory = 0; 91 size_t backtraceSize = 0; 92 93 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); 94 if (info) { 95 uint8_t *ptr = info; 96 size_t count = overallSize / infoSize; 97 98 snprintf(buffer, SIZE, " Allocation count %i\n", count); 99 result.append(buffer); 100 snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); 101 result.append(buffer); 102 103 AllocEntry * entries = new AllocEntry[count]; 104 105 for (size_t i = 0; i < count; i++) { 106 // Each entry should be size_t, size_t, intptr_t[backtraceSize] 107 AllocEntry *e = &entries[i]; 108 109 e->size = *reinterpret_cast<size_t *>(ptr); 110 ptr += sizeof(size_t); 111 112 e->dups = *reinterpret_cast<size_t *>(ptr); 113 ptr += sizeof(size_t); 114 115 e->backtrace = reinterpret_cast<intptr_t *>(ptr); 116 ptr += sizeof(intptr_t) * backtraceSize; 117 } 118 119 // Now we need to sort the entries. They come sorted by size but 120 // not by stack trace which causes problems using diff. 121 bool moved; 122 do { 123 moved = false; 124 for (size_t i = 0; i < (count - 1); i++) { 125 AllocEntry *e1 = &entries[i]; 126 AllocEntry *e2 = &entries[i+1]; 127 128 bool swap = e1->size < e2->size; 129 if (e1->size == e2->size) { 130 for(size_t j = 0; j < backtraceSize; j++) { 131 if (e1->backtrace[j] == e2->backtrace[j]) { 132 continue; 133 } 134 swap = e1->backtrace[j] < e2->backtrace[j]; 135 break; 136 } 137 } 138 if (swap) { 139 AllocEntry t = entries[i]; 140 entries[i] = entries[i+1]; 141 entries[i+1] = t; 142 moved = true; 143 } 144 } 145 } while (moved); 146 147 write(fd, result.string(), result.size()); 148 result.clear(); 149 150 for (size_t i = 0; i < count; i++) { 151 AllocEntry *e = &entries[i]; 152 153 snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); 154 result.append(buffer); 155 for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { 156 if (ct) { 157 result.append(", "); 158 } 159 snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]); 160 result.append(buffer); 161 } 162 result.append("\n"); 163 164 write(fd, result.string(), result.size()); 165 result.clear(); 166 } 167 168 delete[] entries; 169 free_malloc_leak_info(info); 170 } 171} 172 173#else 174// Does nothing 175void dumpMemoryAddresses(int fd) {} 176 177#endif 178} // namespace android 179