summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy McFadden <fadden@android.com>2011-11-07 16:57:54 -0800
committerAndy McFadden <fadden@android.com>2011-11-09 13:32:21 -0800
commitc0a18856ed67b0e77a8202028f27948e1387243d (patch)
tree0336b3232a82bca20a8f2b62b66430fa767f534a
parent2f942b458585539079ef22fa9d7ffc51615522c6 (diff)
downloadandroid_dalvik-c0a18856ed67b0e77a8202028f27948e1387243d.tar.gz
android_dalvik-c0a18856ed67b0e77a8202028f27948e1387243d.tar.bz2
android_dalvik-c0a18856ed67b0e77a8202028f27948e1387243d.zip
Further refinement of card table clear
We're currently using memset() to clear cards out to the growth limit, which on a device configured for 48MB/128MB process caps means we're sitting on 384KB or 1MB of pages. We can reduce that substantially. This change attempts to reduce the memset() length to the currently active portion of the card table, based on the placement of objects in the "live objects" bitmap. This should avoid faulting in card pages that we don't actually need. This is suboptimal when parts of the card table are used briefly and then ignored for a while. An alternative implementation, which uses madvise(DONTNEED) aggressively, is also included (#ifdefed out). Bug 5567332 Change-Id: I7663ae7d15d0aaa8158deed5e331bf05333da6bb
-rw-r--r--vm/alloc/CardTable.cpp48
1 files changed, 41 insertions, 7 deletions
diff --git a/vm/alloc/CardTable.cpp b/vm/alloc/CardTable.cpp
index 212c9d015..333b9f919 100644
--- a/vm/alloc/CardTable.cpp
+++ b/vm/alloc/CardTable.cpp
@@ -104,19 +104,53 @@ void dvmClearCardTable()
* so cards for parts of the heap we haven't expanded into won't be
* allocated physical pages. On the other hand, if we un-map the card
* area, we'll have to fault it back in as we resume dirtying objects,
- * which reduces performance. (Also, "the kernel is free to ignore the
- * advice" makes this sound like something we can't necessarily rely on
- * to synchronously clear memory; may need to memset *and* madvise.)
+ * which reduces performance.
*
- * TODO: use memset() to clear out to the current "soft" limit, and
- * madvise() to clear out the rest.
+ * We don't cause any correctness issues by failing to clear cards; we
+ * just take a performance hit during the second pause of the concurrent
+ * collection. The "advisory" nature of madvise() isn't a big problem.
+ *
+ * What we really want to do is:
+ * (1) zero out all cards that were touched
+ * (2) use madvise() to release any pages that won't be used in the near
+ * future
+ *
+ * For #1, we don't really know which cards were touched, but we can
+ * approximate it with the "live bits max" value, which tells us the
+ * highest start address at which an object was allocated. This may
+ * leave vestigial nonzero entries at the end if temporary objects are
+ * created during a concurrent GC, but that should be harmless. (We
+ * can round up to the end of the card table page to reduce this.)
+ *
+ * For #2, we don't know which pages will be used in the future. Some
+ * simple experiments suggested that a "typical" app will touch about
+ * 60KB of pages while initializing, but drops down to 20-24KB while
+ * idle. We can save a few hundred KB system-wide with aggressive
+ * use of madvise(). The cost of mapping those pages back in is paid
+ * outside of the GC pause, which reduces the impact. (We might be
+ * able to get the benefits by only doing this occasionally, e.g. if
+ * the heap shrinks a lot or we somehow notice that we've been idle.)
*
* Note that cardTableLength is initially set to the growth limit, and
* on request will be expanded to the heap maximum.
*/
assert(gDvm.gcHeap->cardTableBase != NULL);
- memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, gDvm.gcHeap->cardTableLength);
- //madvise(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength, MADV_DONTNEED);
+
+#if 1
+ // zero out cards with memset(), using liveBits as an estimate
+ const HeapBitmap* liveBits = dvmHeapSourceGetLiveBits();
+ size_t maxLiveCard = (liveBits->max - liveBits->base) / GC_CARD_SIZE;
+ maxLiveCard = ALIGN_UP_TO_PAGE_SIZE(maxLiveCard);
+ if (maxLiveCard > gDvm.gcHeap->cardTableLength) {
+ maxLiveCard = gDvm.gcHeap->cardTableLength;
+ }
+
+ memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, maxLiveCard);
+#else
+ // zero out cards with madvise(), discarding all pages in the card table
+ madvise(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength,
+ MADV_DONTNEED);
+#endif
}
/*