1 of 42

State of Chrome's Memory

*

haraken@, tasak@

2017 Jan

*

2 of 42

Background

  • Last year TRIM has achieved a massive amount of memory reductions from all over Chrome

  • To identify the next sweet spots, we investigated the latest status of Chrome's memory on real-world websites

  • This presentation will show you the highlights :D
    • Full results

*

*

3 of 42

Agenda

  • Per-allocator breakdown
    • Understand how much memory is consumed by each allocator (V8, Oilpan, PartitionAlloc, CC, Skia etc)

  • Per-object-type breakdown
    • Understand the top 10 memory-consuming objects in each allocator

*

*

4 of 42

Experimental settings

  • Platform: Linux desktop & Low-memory Android

  • Benchmark: System Health benchmarks
    • load => scroll => user interaction => idle
    • Took memory snapshots every 500 ms

*

*

5 of 42

Per-allocator breakdown (Renderer)

6 of 42

Facebook (Desktop)

*

*

7 of 42

Facebook (Android)

*

*

8 of 42

Facebook (Result)

  • Desktop:
    • V8 is big
    • CC is big but it shrinks once the memory pressure becomes high
      • c.f., CC is small on Android
  • Android:
    • V8 and malloc are big
    • java_heap is big but this is just a measurement issue. Most of it is shared with other processes.

*

*

9 of 42

YouTube (Desktop)

*

*

10 of 42

YouTube (Android)

*

*

11 of 42

YouTube (Result)

  • Desktop:
    • V8 is big

  • Android:
    • V8 and malloc are big
    • CC is very small

*

*

12 of 42

Gmail (Desktop)

*

*

13 of 42

Gmail (Android)

*

*

14 of 42

Gmail (Result)

  • Desktop:
    • V8 is HUGE!

  • Android:
    • V8 and malloc are big
    • V8 is not super big. This is because Mobile Gmail is optimized for V8.

*

*

15 of 42

Imgur (Desktop)

*

*

16 of 42

Imgur (Android)

*

*

17 of 42

Imgur (Result)

  • Desktop:
    • CC is HUGE because Imgur has a lot of images. However, CC is shrinkable.
    • V8 is big

  • Android:
    • V8 and malloc are big
    • CC is very small

*

*

18 of 42

Summary

  • On Desktop, V8 is big. CC is big but it's shrinkable.

  • On Android, V8 and malloc are big

  • However, V8 is no longer the only culprit of the memory bloat. In many websites, (PartitionAlloc + malloc) > V8. We should seriously look into PartitionAlloc and malloc as well as V8.

*

*

19 of 42

Per-allocator breakdown (Browser)

20 of 42

YouTube (Desktop)

*

*

21 of 42

YouTube (Android)

*

*

22 of 42

YouTube (Result)

  • On Desktop
    • malloc is big
    • CC and GPU are big but they are shrinkable
  • On Android
    • malloc is big
    • java_heap is big but most of it is shared with other processes
    • CC and GPU are small
  • We can observe similar results in Facebook, Twitter, Imgur, Gmail etc

*

*

23 of 42

  • ...OK, now you should be wondering what objects are in malloc, right?

  • Next, I'll show you what objects are allocated in malloc, ParitionAlloc and Oilpan :D

*

*

24 of 42

Per-object-type breakdown

25 of 42

PartitionAlloc (Renderer, Android)

*

*

26 of 42

PartitionAlloc (Renderer, Android)

  • WTF::StringImpl
    • We confirmed that most of the Strings are allocated by JavaScript source strings

  • WTF::ArrayBufferContents
    • This is allocated by user scripts
    • Maybe would it be helpful to compress it?

*

*

27 of 42

How can we drop JS source strings?

  • The current V8 accesses JS source strings every time it compiles a JS function (i.e., very frequently)
    • So, for performance reasons, we shouldn't drop JS source strings

  • This behavior is going to be fixed once Turbofan & Ignition ships :)

*

*

28 of 42

How can we drop JS source strings?

  • Option 1: Lock the original resources on a disk cache so that we can reload the JS source strings at any time
  • Option 2: Dump the JS source strings to a file and drop them from memory
  • Option 3: Introduce "SwappableMemory" and allocate the JS source strings on it
  • Option 4: Compress the JS source strings

*

*

29 of 42

Oilpan (Renderer, Desktop)

*

*

30 of 42

Oilpan (Renderer, Desktop)

  • Node, StylePropertySet, Resource and CSSValue are big

  • However, Oilpan's usage is not a main memory consumer in a renderer process. So, reducing sizeof(Node etc) wouldn't have a big impact.

*

*

31 of 42

malloc (Renderer, Desktop)

*

*

32 of 42

malloc (Renderer, Desktop)

  • SkRWBuffer::append
    • This is used by encoded images
    • Previously there was a bug that encoded images were duplicated between Skia and PartitionAlloc. When hajimehoshi@ removed the duplication, it reduced ~15 MB from image-intensive websites
    • i.e., if we can drop the encoded images, we can get another ~15 MB win

*

*

33 of 42

How can we drop encoded images?

  • Option 1: Lock the original resources on a disk cache so that we can recreate the encoded images

  • Option 2: Dump the encoded images to a file and drop them from memory

  • Option 3: Implement "SwappableMemory" and allocate the encoded images on it

*

*

34 of 42

malloc (Browser, Android)

*

*

35 of 42

malloc (Browser, Android)

  • std::string, std::vector etc are big but we don't know where they're allocated

  • Per-object-type breakdown doesn't look like a good way to analyze malloc on a browser process
    • ssid@'s per-directory breakdown is more useful
    • net/ and sync/ are big

*

*

36 of 42

Summary

37 of 42

Summary

  • V8 is big but no longer the only culprit of the memory bloat
    • In many websites, (PartitionAlloc + malloc) > V8

  • To achieve the next massive reductions, we should look at:
    • JS source strings (WTF::StringImpl)
    • encoded images (SkRWBuffer::append)
    • net/ and sync/ in a browser process

*

*

38 of 42

  • ...In this presentation, I've focused on memory reductions of some specific allocators / objects

  • TRIM is also working on more general things

*

*

39 of 42

General reduction efforts

40 of 42

Goals

  • Android:
    • Reduce memory consumption of a foreground tab
    • Reduce # of OOMs
      • On <512 MB devices, 99% of renderer crashes are due to OOM
  • Desktop:
    • Reduce memory consumption of background tabs
    • Give more memory budget to a foreground tab (and make it faster)

*

*

41 of 42

Memory Coordinator

  • Memory Pressure Listener => Memory Coordinator
    • THROTTLED state (to throttle future allocations)
    • Purge notifications (to purge past allocations)

  • Purge+Suspend Purge+Throttle
    • Purge as much memory as possible from background tabs => aggressively throttle

*

*

42 of 42

Low-memory mode (isLowEndDevice())

  • Enabled on <512 MB devices
    • Current feature list using the low-memory mode

  • Support the low-memory mode on more features

  • In long term, make the low-memory mode a dynamic state of Memory Coordinator

*

*