Building Memory-efficient Java Applications: Practices and Challenges

Similar documents
From Java Code to Java Heap Understanding the Memory Usage of Your Application

PVS. Empirical Study of Usage and Performance of Java Collections. Diego Costa, 1 Artur Andrzejak, 1 Janos Seboek, 2 David Lo

Effec%ve So*ware. Lecture 9: JVM - Memory Analysis, Data Structures, Object Alloca=on. David Šišlák

Collections Questions

Computer Memory. Data Structures and Algorithms CSE 373 SP 18 - KASEY CHAMPION 1

Understanding Performance in Large-scale Framework-based Systems

CS61B Lecture #17. Last modified: Mon Oct 1 13:40: CS61B: Lecture #17 1

Windows Java address space

CS399 New Beginnings. Jonathan Walpole

Application Development in JAVA. Data Types, Variable, Comments & Operators. Part I: Core Java (J2SE) Getting Started

Learning to Play Well With Others

Learning to Play Well With Others

Data Structures - CSCI 102. CS102 Hash Tables. Prof. Tejada. Copyright Sheila Tejada

Copyright 2012, Oracle and/or its affiliates. All rights reserved.

Is It Possible to Code an Efficient Software Switch?

Performance of Non-Moving Garbage Collectors. Hans-J. Boehm HP Labs

Transparent Pointer Compression for Linked Data Structures

+ Abstract Data Types

Java Collections Framework reloaded

Lecture 16: Case Study: The Java Collections API

Efficient Java (with Stratosphere) Arvid Heise, Large Scale Duplicate Detection

DOWNLOAD PDF CORE JAVA APTITUDE QUESTIONS AND ANSWERS

CSE 373: Data Structures and Algorithms. Memory and Locality. Autumn Shrirang (Shri) Mare

Method-Level Phase Behavior in Java Workloads

Assumptions. History

Agenda. CSE P 501 Compilers. Java Implementation Overview. JVM Architecture. JVM Runtime Data Areas (1) JVM Data Types. CSE P 501 Su04 T-1

JAVA. Duration: 2 Months

The New Java Technology Memory Model

Implementing a List in Java. CSE 143 Java. Just an Illusion? List Interface (review) Using an Array to Implement a List.

StackVsHeap SPL/2010 SPL/20

Programming Style and Optimisations - An Overview

CSE P 501 Compilers. Java Implementation JVMs, JITs &c Hal Perkins Winter /11/ Hal Perkins & UW CSE V-1

Virtualizing JBoss Enterprise Middleware with Azul

Top Ten Enterprise Java performance problems. Vincent Partington Xebia

Overview. Constructors and destructors Virtual functions Single inheritance Multiple inheritance RTTI Templates Exceptions Operator Overloading

High Performance Managed Languages. Martin Thompson

Three OPTIMIZING. Your System for Photoshop. Tuning for Performance

Attila Szegedi, Software

Fundamental language mechanisms

CS 345. Garbage Collection. Vitaly Shmatikov. slide 1

Compact Off-Heap Structures in the Java Language

Ch. 11: References & the Copy-Constructor. - continued -

Memory management has always involved tradeoffs between numerous optimization possibilities: Schemes to manage problem fall into roughly two camps

Java HashMap Interview Questions

JAVA WRAPPER CLASSES

by Marina Cholakyan, Hyduke Noshadi, Sepehr Sahba and Young Cha

Performance metrics for caches

Lightweight Remote Procedure Call

CMSC 132: Object-Oriented Programming II. Effective Java. Department of Computer Science University of Maryland, College Park

Heap Compression for Memory-Constrained Java

Object Oriented Programming: In this course we began an introduction to programming from an object-oriented approach.

Deconstructing Java TM

Faster Objects and Arrays. Closing the [last?] inherent C vs. Java speed gap

MemoryLint. Petr Nejedlý, Radim Kubacki SUN Microsystems, BOF-9066

Introducing Hashing. Chapter 21. Copyright 2012 by Pearson Education, Inc. All rights reserved

Principles of Software Construction: Objects, Design, and Concurrency

Midterm 2. 7] Explain in your own words the concept of a handle class and how it s implemented in C++: What s wrong with this answer?

Java Collections The Force Awakens.

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 11

Habanero Extreme Scale Software Research Project

Peers Techno log ies Pv t. L td. Core Java & Core Java &Adv Adv Java Java

5/23/2015. Core Java Syllabus. VikRam ShaRma

Azul Systems, Inc.

Implementing a List in Java. CSC 143 Java. List Interface (review) Just an Illusion? Using an Array to Implement a List CSC

CS370 Operating Systems

JAVA. 1. Introduction to JAVA

Dynamic Dispatch and Duck Typing. L25: Modern Compiler Design

Java Without the Jitter

The Dynamic Typing Interlude

Continuous Object Access Profiling and Optimizations to Overcome the Memory Wall and Bloat

CSE 373 OCTOBER 23 RD MEMORY AND HARDWARE

Thin Locks: Featherweight Synchronization for Java

Control Hazards. Branch Prediction

Shenandoah An ultra-low pause time Garbage Collector for OpenJDK. Christine H. Flood Roman Kennke

ECE 550D Fundamentals of Computer Systems and Engineering. Fall 2017

Core Java Syllabus. Overview

Review. CSE 143 Java. A Magical Strategy. Hash Function Example. Want to implement Sets of objects Want fast contains( ), add( )

A new Mono GC. Paolo Molaro October 25, 2006

The name of the Show What will you enjoy learning?

Control Abstraction. Hwansoo Han

<Insert Picture Here> Get on the Grid. JVM Language Summit Getting Started Guide. Cameron Purdy, VP of Development, Oracle

Core Java SYLLABUS COVERAGE SYLLABUS IN DETAILS

Generics. IRS W-9 Form

The Collections API. Lecture Objectives. The Collections API. Mark Allen Weiss

Programs in memory. The layout of memory is roughly:

CS211 Computers and Programming Matthew Harris and Alexa Sharp July 9, Boggle

Outline EEL 5764 Graduate Computer Architecture. Chapter 3 Limits to ILP and Simultaneous Multithreading. Overcoming Limits - What do we need??

HASH TABLE BY AKARSH KUMAR

DESIGN PATTERN - INTERVIEW QUESTIONS

Get started with the Java Collections Framework By Dan Becker

All code must follow best practices. Part (but not all) of this is adhering to the following guidelines:

Profiling & Optimization

Winter 2016 COMP-250: Introduction to Computer Science. Lecture 6, January 28, 2016

Virtual Memory. Kevin Webb Swarthmore College March 8, 2018

Java Collections. Readings and References. Collections Framework. Java 2 Collections. CSE 403, Spring 2004 Software Engineering

Garbage Collection (1)

ADTs, Arrays, Linked Lists

Key Point. What are Cache lines

Summer Final Exam Review Session August 5, 2009

Advanced Programming & C++ Language

Transcription:

Building Memory-efficient Java Applications: Practices and Challenges Nick Mitchell, Gary Sevitsky (presenting) IBM TJ Watson Research Center Hawthorne, NY USA Copyright is held by the author/owner(s). ACM SIGPLAN PLDI 2009, Dublin, Ireland

Quiz

Small boxes? Q: What is the size ratio of Integer to int? a. 1 : 1 b. 1.33 : 1 c. 2 : 1 d.? Assume 32-bit platform

Small things? Q: How many bytes in an 8-character String? a. 8 b. 16 c. 28 d.? Assume 32-bit platform

Bigger? Better? Q: Which of the following is true about HashSet relative to HashMap a. does less, smaller b. does more, smaller c. similar amount of functionality, same size d.?

The big pile-up Heaps are getting bigger Grown from 500M to 2-3G or more in the past few years But not necessarily supporting more users or functions Surprisingly common: requiring 1G memory to support a few hundred users saving 500K session state per user requiring 2M for a text index per simple document creating 100K temporary objects per web hit Consequences for scalability, power usage, and performance

Common thread It is easy to build systems with large memory requirements for the work accomplished Overhead of representation of data can be 50-90% Not counting duplicate data and unused data

The big pile-up Not a reflection on the quality of programmers many are expert More abstractions = less awareness of costs It is easy for costs to pile up, just piecing together building blocks The iceberg effect: App Frameworks Frameworks Frameworks Frameworks

Myths

Things are fine Objects (or Strings, HashMaps, ) are cheap Frameworks are written by experts, so they ve been optimized (for my use case!) The JIT and GC will fix everything

Things are not fine I knew foo was expensive; I didn t know it was this expensive! It s no use: O-O plus Java is always expensive Efficiency is incompatible with good design

Data type health One Double Double Double 24 bytes JVM-imposed overhead: 16 bytes double data: 8 bytes 33% is actual data 67% is the representation overhead From one 32-bit JVM. Varies with JVM, architecture.

Data type health Example: An 8-character String String 8-char String 64 bytes only 25% is the actual data 75% is overhead of representation JVM overhead 16 bytes char[] bookkeeping fields 12 bytes pointer 4 bytes would need 96 characters for overhead to be 20% or less chars JVM overhead 16 bytes data 16 bytes

Collection health A 100-entry TreeMap TreeMap x1 = 3.9KB How does a TreeMap spend its bytes? TreeMap TreeMap$Entry Fixed overhead: 48 bytes Collections have fixed and variable costs Per-entry overhead: 40 bytes data

Data structure health TreeMap<Double, Double> (100 entries) TreeMap x1 = 3.9KB 100% overhead 100 100 82% overhead overall Design enables updates while maintaining order Double x100 = 2.3KB Double x100 = 2.3KB 67% overhead Is it worth the price?

Data structure health Alternative implementation (100 entries) double[] 1x = 816 bytes double[] 1x = 816 bytes 2% overhead Binary search against sorted array Less functionality suitable for loadthen-use scenario 2% overhead

Collections involving scalars Case study: monitoring infrastructure TreeMap x52 = 537MB Data structure took 1.2GB 265K 265K Overhead is still 82% at this giant scale Double x13.4m = 342MB Double x13.4m = 342MB Some alternative scalar maps/collections available, with much lower overhead

Health as a gauge of scalability TreeMap<Double, Double> Overhead is still 82% of cost Data Overhead 88% 82% Overhead is not amortized in this design 1 100K 200K 300K 400K High constant cost per element: 88 bytes

Health as a gauge of scalability Alternative implementation double[] double[] ~ 0% overhead Overhead starts out low, quickly goes to 0 Data Overhead Cost per element is 16 bytes, pure data 2% 0% 1 100K 200K 300K 400K

Background: the cost of objects Boolean 16 bytes header 12 bytes boolean 1 byte alignment 3 bytes JVM & hardware impose costs on objects. Can be substantial for small objects Double 24 bytes header 12 bytes double 8 bytes alignment 4 bytes Headers enable functionality and performance optimizations char[2] 24 bytes 8-byte alignment in this JVM header 16 bytes From experiment on one 32-bit JVM 2 chars 4 bytes alignment 4 bytes Costs vary with JVM, architecture

Example: An 8-character String The cost of delegation 8-char String 64 bytes 31% is overhead due to modeling as two objects String Effect varies with size of String JVM overhead 16 bytes bookkeeping fields 12 bytes pointer 4 bytes char[] chars JVM overhead 16 bytes data 16 bytes

Fine-grained modeling Case study: server framework, part of connection Request info Request x46k = 67MB one Request 34 instances to represent a request. Cost: 1.5K per request. Will not scale. Entry Entry Entry To From Contact 36% of cost is delegation overhead NameAddress NameAddress NameAddress Constant overhead per Request Url Url Url Params Params Params Params Params Can magnify the costs of other choices

Example: An 8-character String 32- vs. 64-bit String 8-char String 96 bytes 50% larger Delegated design is responsible for extra object header and pointer costs JVM overhead 24 bytes bookkeeping fields 12 bytes pointer 8 bytes alignment 4 bytes Fine-grained designs incur especially high costs char[] JVM overhead 24 bytes chars data 16 bytes

Data type modeling: challenges for developers Java s limited data modeling means tradeoffs require care Moving rarely-used fields to side objects incurs delegation costs Moving sparse fields to a map incurs high map entry costs Verifying actual costs and benefits is essential Fixing problems of high-overhead data usually means refactoring data models Not easy late in the cycle Using interfaces and factories up front can help

Data type modeling: community challenges Many more objects and pointers than other languages x high per-object cost = 35% delegation overhead avg in heaps Only two options for achieving variation both are expensive delegation vs. unused fields (large base classes) both limit higher-level choices and magnify carelessness Consequences all the way up the stack Primitives as object(s): String, Date, BigDecimal, boxed scalars Collections suffer these limitations Many layers of frameworks implementing systems functionality Solutions in the language / runtime?

Small collections in context Case study: Planning system, level graph edges Index HashMap x1 = 1.8MB Two examples of small high-overhead collections Keys ArrayList x65k = 3.1MB Values HashSet x65k = 16MB 297K edges cost 31MB Overhead of representation: 83% 1 Vertex 1 Level Integer x65k = 1MB Data 4.5 Edge x297k = 9MB Overhead will not improve with more vertices

Small collections in context Map with multiple values per entry Index HashMap x1 = 1.8MB Only 5% of sets had more than a few elements each Keys ArrayList x65k = 3.1MB Values HashSet x65k = 16MB 1 1 Vertex Level Data 4.5 Integer x65k = 1MB Edge x297k = 9MB

Inside the Java collections HashSet: many embedded usage assumptions Reuse of library code was considered important. Cost: 24 bytes/set + 4/entry HashSet Assumes entry, key, value sets all commonly used. Cost: 12 bytes HashMap array Total cost: 72+ bytes fixed 28 bytes/entry Default capacity 16. For 5-entry set: 44+ bytes empty slots. Not a good choice for small collections Users, look before you leap always measure Framework designers, beware making usage assumptions HashMap$Entry Key Value

Small collections in context Map with multiple values per entry Index HashMap x1 = 1.8MB Remedy Switched to ArrayList. Saved 77% of that region. Keys ArrayList x65k = 3.1MB 1 Vertex 1 Level Integer x65k = 1MB Values Data ArrayList x65k = 3.7MB 4.5 Edge x297k = 9MB HashSet functionality was not worth the cost. Uniqueness already guaranteed elsewhere Wish list Gracefully-growing collections

Small collections in context Multipart key as 2-element ArrayList Index HashMap x1 = 1.8MB ArrayList has a high fixed cost. Also required boxing of integers. Keys ArrayList x65k = 3.1MB Values ArrayList x65k = 3.7MB 1 1 Vertex Level Data 4.5 Integer x65k = 1MB Edge x297k = 9MB

ArrayList Inside the Java collections ArrayList Cost of minimally sized 2-element ArrayList: 40 bytes fixed + 4 bytes/entry Much lower fixed and variable costs than HashMap or HashSet Fixed costs from delegation plus bookkeeping fields. Object[] Fixed costs can still add up for small collections entry Default size and growth policy can mean overhead from empty slots entry

Small collections in context Multipart key class Index HashMap x1 = 1.8MB Remedy: Introduced Pair class (Vertex, int level) Keys Pair x65k = 1.3MB Values ArrayList x65k = 3.7MB Again, functionality of original design was not worth the cost 1 Vertex Data 4.5 Reduced key overhead by 68% Edge x297k = 9MB

Multipart key Case study: Apache Commons MultiKeyMap MultiKeyMap Apache Commons collections frameworks has the same pattern Array Paying for flexibility that s not needed MultiKey Cost: additional 20 bytes per entry Array KeyPart1 KeyPart2 Could have easily created specialized MultiKey2, MultiKey3, etc. to avoid delegation cost

Growth policies Example: creating default-size ArrayLists Keys Pair x65k = 1.3MB 1 Vertex Index HashMap x1 = 1.8MB Would be 3.7M with optimal sizing Values Data ArrayList x65k = 5.2MB 4.5 Edge x297k = 9MB 28% overhead in ArrayLists just from empty slots collections optimized for growth large defaults and jumps doubling 10% tax on some copies Remedies: Set initial capacity trimtosize() after load

Inside the Java Collections Cost of a 2-element collection Minimal size (bytes) Default size (bytes) # of slots for 2 elements using default size LinkedList 96 96 3 ArrayList 48 or 56 80 or 88 10 HashMap 116 or 168 168 16 HashSet 132 or 184 184 16 From experiments with a few different JVMs, all 32-bit.

The cost of empty collections Case study: CRM system, part of session data Index SessionData x330 = under 1MB Person 3 Small run had 26M of session data. Will not scale. 210 empty collections per session = 28% of session cost other structures 15 MB Profile x1.95k = 4.6MB 70 ArrayList x101k = 7.9MB Remedies: Lazily allocate Collections.emptySet() Avoid giving out references

The Not-so-empty Collections HashMap ArrayList Array Array 10 slot default from API spec Minimum of 2 objects each component parts are always allocated HashSet LinkedList Default sizing increases cost (e.g. 16 elements for HashMap/HashSet) HashMap LinkedList$Entry Array Always allocates a sentinel entry

Inside the Java Collections Cost of an empty collection Minimal size (bytes) Default size (bytes) Default # of slots LinkedList 48 48 1 sentinel entry ArrayList 40 or 48 80 or 88 10 HashMap 56 or 120 120 16 HashSet 72 or 136 136 16 From experiments with a few different JVMs, all 32-bit.

Small concurrent maps Case study: Chat server framework Active sessions Session Concurrent- HashMap x1 = 4MB Chat session x110k = 10MB Subscribers Concurrent- HashMap x110k = 173MB Subscriber 110K 1 1 Subscriber x110k = 4.2MB Nested CHMs: > 1600 bytes each! Cost was 90% of this structure; 10-20% of total heap What went wrong: Library not intended for use at this scale Concurrency requirements were different at fine vs. coarse grain

Small concurrent maps Case study: Chat server framework Active sessions Concurrent- HashMap x1 = 4MB Remedies: First considered reducing width of inner ConcurrentHashMap from 16 to 3. Savings: 67% Session 110K Chat session x110k = 10MB Subscribers Hashtable x110k = 17M Subscriber 1 1 Subscriber x110k = 4.2MB Used Hashtable, since high level of concurrency not needed. Savings: 90 + % Note: Hashtable less expensive than similar Collections$ SynchronizedMap

Inside the Java Collections Wrapped collections Collections$ SynchronizedMap Collections$ UnmodifiableMap Design is based on delegation HashMap 28 bytes HashMap Costs are significant when collections are small Fine for larger collections

Small wrapped collections Case study: media e-commerce site (64-bit) Cache Element Concurrent- HashMap x1 = 3.8MB 64K 108MB for UnmodifiableMap wrappers. 56 bytes each Twice the cost as on a 32-bit JVM Titles Unmodifiable- Map x1.9m = 106M 1 HashMap x1.9m = 359MB Titles Title CachedElement x63k = 137MB 32 Unmodifiable- Map x1.9m = 465MB 1.01 String x2m = 156MB What went wrong: Functionality not worth the cost at this scale. Unmodifiable serves a developmenttime purpose

Inside the Java Collections Standard collections: per-entry costs. LinkedList Per-entry cost (bytes) 24 Plus any overhead of introducing a key or value object ArrayList 4 HashMap 28 or 36 HashSet 28 or 36 From experiments with a few different JVMs, all 32-bit. Excludes amortized per-collection costs such as empty array slots. Includes pointer to entry.

The standard collections JDK Standard Collections Speed has been the focus, not footprint IBM (Harmony) and Sun implementations not that different in footprint Hard-wired assumptions, few policy knobs (e.g. growth policies) Specialized collections are worth learning about: IdentityHashMap, WeakHashMap, ConcurrentHashMap, etc.

Collections alternatives Apache Commons Many useful collections: Flat3Map, MultiMap, MultiKeyMap Focus is mostly on functionality. Maps allow some extension. Footprint similar to standard, with a few exceptions GNU Trove Many space-efficient implementations e.g. scalar collections e.g. list entries without delegation cost Cliff Click nonblocking; Javolution; Amino Specialized collections within frameworks you use Important: check your corporate policy re: specific open source frameworks

Duplicate, immutable data Case study: Text analysis system, concordance Concordance- Entry x131k = 41MB ConcordanceEntry 17% of cost due to duplication of Type and its String data Only a small number of immutable Types Annotation Type 1 1 What went wrong? Interface design did not provide for sharing Full cost of duplication was hidden String 1 char[] 1 Remedy Use shared immutable factory pattern

Background: sharing low-level data String.intern() You specify which Strings to share Shares the String object and the character array Make sure it s worth it, since there is a space cost Myth that is causes memory leaks Though can hit permspace limits Boxed scalars Integer.valueOf(), Boolean.valueOf(), etc. Shares some common values (not all) Make sure you don t rely on ==

Expensive temporaries Example: SimpleDateFormat Decimal- Format SimpleDateFormat Gregorian- Calendar String[] String[] Costly construction process. Each call to the default constructor results in: 123 calls to 55 distinct methods 44 new instances Decimal- Format- Symbols int[] Date TimeZone Designed for costs to be amortized over many uses Remedy: reuse via a local variable or thread-local storage