madvise away app image dex cache arrays

This saves ram and PSS by reducing the number of mapped pages. Also
PROT_NONE the dex cache arrays section to make accesses fault.

virtual                     shared   shared  private  private
size      RSS      PSS    clean    dirty    clean    dirty     swap
-------- -------- -------- -------- -------- -------- -------- --------
Before:
/data/app/com.facebook.katana-2/oat/arm/base.art
52484    52144    43522    17244        0        0    34900        0
/data/app/com.google.android.apps.maps-2/oat/arm/base.art
 6876     6816     6816        0        0     2008     4808        0

After:
/data/app/com.facebook.katana-2/oat/arm/base.art
52484    49204    42032    14344        0        0    34860        0
/data/app/com.google.android.apps.maps-2/oat/arm/base.art
 6876     6388     6388        0        0     1584     4804        0

Bug: 22858531

Change-Id: I87888a7c1518a92736dbd29eed338e7472ae3587
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e4f492b..205ba3e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1669,6 +1669,22 @@
                                                          forward_dex_cache_arrays);
       class_table->Visit(visitor);
     }
+    // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss.
+    // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and
+    // mark as PROT_NONE to catch any invalid accesses.
+    if (forward_dex_cache_arrays) {
+      const ImageSection& dex_cache_section = header.GetImageSection(
+          ImageHeader::kSectionDexCacheArrays);
+      uint8_t* section_begin = AlignUp(space->Begin() + dex_cache_section.Offset(), kPageSize);
+      uint8_t* section_end = AlignDown(space->Begin() + dex_cache_section.End(), kPageSize);
+      if (section_begin < section_end) {
+        madvise(section_begin, section_end - section_begin, MADV_DONTNEED);
+        mprotect(section_begin, section_end - section_begin, PROT_NONE);
+        VLOG(image) << "Released and protected dex cache array image section from "
+                    << reinterpret_cast<const void*>(section_begin) << "-"
+                    << reinterpret_cast<const void*>(section_end);
+      }
+    }
   }
   VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time);
   return true;