2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Reference table management.
22 * Initialize a ReferenceTable structure.
24 bool dvmInitReferenceTable(ReferenceTable* pRef, int initialCount,
27 assert(initialCount > 0);
28 assert(initialCount <= maxCount);
30 pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
31 if (pRef->table == NULL)
34 memset(pRef->table, 0xdd, initialCount * sizeof(Object*));
36 pRef->nextEntry = pRef->table;
37 pRef->allocEntries = initialCount;
38 pRef->maxEntries = maxCount;
44 * Clears out the contents of a ReferenceTable, freeing allocated storage.
46 void dvmClearReferenceTable(ReferenceTable* pRef)
49 pRef->table = pRef->nextEntry = NULL;
50 pRef->allocEntries = pRef->maxEntries = -1;
54 * Add "obj" to "pRef".
56 bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj)
58 assert(dvmIsValidObject(obj));
60 assert(pRef->table != NULL);
62 if (pRef->nextEntry == pRef->table + pRef->maxEntries) {
63 LOGW("ReferenceTable overflow (max=%d)\n", pRef->maxEntries);
65 } else if (pRef->nextEntry == pRef->table + pRef->allocEntries) {
69 newSize = pRef->allocEntries * 2;
70 if (newSize > pRef->maxEntries)
71 newSize = pRef->maxEntries;
72 assert(newSize > pRef->allocEntries);
74 newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
75 if (newTable == NULL) {
76 LOGE("Unable to expand ref table (from %d to %d %d-byte entries)\n",
77 pRef->allocEntries, newSize, sizeof(Object*));
80 LOGVV("Growing %p from %d to %d\n", pRef, pRef->allocEntries, newSize);
82 /* update entries; adjust "nextEntry" in case memory moved */
83 pRef->nextEntry = newTable + (pRef->nextEntry - pRef->table);
84 pRef->table = newTable;
85 pRef->allocEntries = newSize;
88 *pRef->nextEntry++ = obj;
93 * Returns NULL if not found.
95 Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** top,
100 ptr = pRef->nextEntry;
101 while (--ptr >= top) {
109 * Remove "obj" from "pRef". We start at the end of the list (where the
110 * most-recently-added element is), and stop searching for a match after
111 * examining the element at "top".
113 * Most of the time "obj" is at or near the end of the list. If not, we
116 bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** top,
121 assert(pRef->table != NULL);
124 * Scan from the most-recently-added entry up to the top entry for
127 ptr = dvmFindInReferenceTable(pRef, top, obj);
135 int moveCount = pRef->nextEntry - ptr;
136 if (moveCount != 0) {
137 /* remove from middle, slide the rest down */
138 memmove(ptr, ptr+1, moveCount * sizeof(Object*));
139 //LOGV("LREF delete %p, shift %d down\n", obj, moveCount);
141 /* last entry, falls off the end */
142 //LOGV("LREF delete %p from end\n", obj);
149 * This is a qsort() callback. We sort Object* by class, allocation size,
150 * and then by the Object* itself.
152 static int compareObject(const void* vobj1, const void* vobj2)
154 Object* obj1 = *((Object**) vobj1);
155 Object* obj2 = *((Object**) vobj2);
157 if (obj1 == NULL || obj2 == NULL)
158 return (u1*)obj1 - (u1*)obj2;
160 if (obj1->clazz != obj2->clazz) {
161 return (u1*)obj1->clazz - (u1*)obj2->clazz;
163 int size1 = dvmObjectSizeInHeap(obj1);
164 int size2 = dvmObjectSizeInHeap(obj2);
165 if (size1 != size2) {
166 return size1 - size2;
168 return (u1*)obj1 - (u1*)obj2;
174 * Log an object with some additional info.
176 * Pass in the number of additional elements that are identical to or
177 * equivalent to the original.
179 static void logObject(Object* obj, int size, int identical, int equiv)
182 LOGW(" NULL reference (count=%d)\n", equiv);
186 if (identical + equiv != 0) {
187 LOGW("%5d of %s %dB (%d unique)\n", identical + equiv +1,
188 obj->clazz->descriptor, size, equiv +1);
190 LOGW("%5d of %s %dB\n", identical + equiv +1,
191 obj->clazz->descriptor, size);
196 * Dump the contents of a ReferenceTable to the log.
198 * The caller should lock any external sync before calling.
200 * (This was originally written to be tolerant of null entries in the table.
201 * I don't think that can happen anymore.)
203 void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
205 const int kLast = 10;
206 int count = dvmReferenceTableEntries(pRef);
211 LOGW("Reference table has no entries\n");
217 * Dump the most recent N entries.
219 LOGW("Last %d entries in %s reference table:\n", kLast, descr);
220 refs = pRef->table; // use unsorted list
222 int start = count - kLast;
226 for (i = start; i < count; i++) {
227 size = (refs[i] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i]);
228 Object* ref = refs[i];
229 if (ref->clazz == gDvm.classJavaLangClass) {
230 ClassObject* clazz = (ClassObject*) ref;
231 LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", i, ref,
232 (refs[i] == NULL) ? "-" : ref->clazz->descriptor,
233 clazz->descriptor, size);
235 LOGW("%5d: %p cls=%s (%d bytes)\n", i, ref,
236 (refs[i] == NULL) ? "-" : ref->clazz->descriptor, size);
241 * Make a copy of the table, and sort it.
243 Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
244 memcpy(tableCopy, pRef->table, sizeof(Object*) * count);
245 qsort(tableCopy, count, sizeof(Object*), compareObject);
246 refs = tableCopy; // use sorted list
249 * Dump uniquified table summary. While we're at it, generate a
250 * cumulative total amount of pinned memory based on the unique entries.
252 LOGW("%s reference table summary (%d entries):\n", descr, count);
253 int equiv, identical, total;
254 total = equiv = identical = 0;
255 for (i = 1; i < count; i++) {
256 size = (refs[i-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i-1]);
258 if (refs[i] == refs[i-1]) {
259 /* same reference, added more than once */
261 } else if (refs[i]->clazz == refs[i-1]->clazz &&
262 (int) dvmObjectSizeInHeap(refs[i]) == size)
264 /* same class / size, different object */
268 /* different class */
270 logObject(refs[i-1], size, identical, equiv);
271 equiv = identical = 0;
275 /* handle the last entry (everything above outputs refs[i-1]) */
276 size = (refs[count-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[count-1]);
278 logObject(refs[count-1], size, identical, equiv);
280 LOGW("Memory held directly by native code is %d bytes\n", total);