diff options
author | Andy McFadden <fadden@android.com> | 2011-11-07 16:57:54 -0800 |
---|---|---|
committer | Andy McFadden <fadden@android.com> | 2011-11-09 13:32:21 -0800 |
commit | c0a18856ed67b0e77a8202028f27948e1387243d (patch) | |
tree | 0336b3232a82bca20a8f2b62b66430fa767f534a | |
parent | 2f942b458585539079ef22fa9d7ffc51615522c6 (diff) | |
download | android_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.cpp | 48 |
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 } /* |