Dalvik VM Internals
Dalvik VM Internals
Dan Bornstein
Google
• Intro
• Memory
• CPU
• Advice
• Conclusion
Dalvík, Iceland
The Big Picture
The Big Picture
What is the Dalvik VM?
It is a virtual machine to…
• Intro
• Memory
• CPU
• Advice
• Conclusion
Problem: Memory Efficiency
class_defs
data
Dex File Anatomy
header
"Hello World"
"Lcom/google/Blort;" int
"println" string_ids String[]
… com.google.Blort
…
void fn(int)
type_ids
double fn(Object, int)
String fn() proto_ids String.offset
… Integer.MAX_VALUE
…
field_ids
PrintStream.println(…)
Collection.size()
… method_ids
class_defs
data
Dex File Anatomy
header
"Hello World"
"Lcom/google/Blort;" int
"println" string_ids String[]
… com.google.Blort
…
void fn(int)
type_ids
double fn(Object, int)
String fn() proto_ids String.offset
… Integer.MAX_VALUE
…
field_ids
PrintStream.println(…)
Collection.size()
… method_ids
class_defs
data
Dex File Anatomy
header
"Hello World"
"Lcom/google/Blort;" int
"println" string_ids String[]
… com.google.Blort
…
void fn(int)
type_ids
double fn(Object, int)
String fn() proto_ids String.offset
… Integer.MAX_VALUE
…
field_ids
PrintStream.println(…)
Collection.size()
… method_ids
class_defs
data
Dex File Anatomy
.jar file
.class file
heterogeneous
constant pool .dex file
string_ids
other data constant pool
type_ids
constant pool
.class file proto_ids
heterogeneous constant pool
constant pool field_ids
constant pool
method_ids
other data
constant pool
.class file
heterogeneous other data
constant pool
other data
Shared Constant Pool
public interface Zapper {
public String zap(String s, Object o);
}
public class Blort implements Zapper {
public String zap(String s, Object o) {
...;
}
}
public class ZapUser {
public void useZap(Zapper z) {
z.zap(...);
}
}
Shared Constant Pool
Original .class files
class Zapper class Blort
"Zapper" "SourceFile" "Blort" "Zapper"
"zap" "java/lang/Object" method ref "zap" "LineNumberTable"
"Zapper.java" "Blort.java" "(Ljava/lang/String;Ljava/lang/
"(Ljava/lang/String;Ljava/lang/ "Code" Object;)Ljava/lang/String;"
Object;)Ljava/lang/String;"
method ref "java/lang/Object"
"<init>" "SourceFile"
"()V"
class ZapUser
"ZapUser" "Zapper" "ZapUser.java"
method ref "zap" "LineNumberTable"
"(Ljava/lang/String;Ljava/lang/
"Code" Object;)Ljava/lang/String;"
method ref "java/lang/Object"
"<init>" "SourceFile"
"()V"
"useZap" "(LZapper;)V"
Shared Constant Pool
Original .class files
class Zapper class Blort
"Zapper" "SourceFile" "Blort" "Zapper"
"zap" "java/lang/Object" method ref "zap" "LineNumberTable"
"Zapper.java" "Blort.java" "(Ljava/lang/String;Ljava/lang/
"(Ljava/lang/String;Ljava/lang/ "Code" Object;)Ljava/lang/String;"
Object;)Ljava/lang/String;"
method ref "java/lang/Object"
"<init>" "SourceFile"
"()V"
class ZapUser
"ZapUser" "Zapper" "ZapUser.java"
method ref "zap" "LineNumberTable"
"(Ljava/lang/String;Ljava/lang/
"Code" Object;)Ljava/lang/String;"
method ref "java/lang/Object"
"<init>" "SourceFile"
"()V"
"useZap" "(LZapper;)V"
Shared Constant Pool
Original .class files
class Zapper class Blort
"Zapper" "SourceFile" "Blort" "Zapper"
"zap" "java/lang/Object" method ref "zap" "LineNumberTable"
"Zapper.java" "Blort.java" "(Ljava/lang/String;Ljava/lang/
"(Ljava/lang/String;Ljava/lang/ "Code" Object;)Ljava/lang/String;"
Object;)Ljava/lang/String;"
method ref "java/lang/Object"
"<init>" "SourceFile"
"()V"
class ZapUser
"ZapUser" "Zapper" "ZapUser.java"
method ref "zap" "LineNumberTable"
"(Ljava/lang/String;Ljava/lang/
"Code" Object;)Ljava/lang/String;"
method ref "java/lang/Object"
"<init>" "SourceFile"
"()V"
"useZap" "(LZapper;)V"
Shared Constant Pool
.dex file
method id "useZap"
"Blort.java"
"LZapUser;" proto id "Zapper.java"
"ZapUser.java"
method id
"LZapper;"
"<init>"
proto id "V"
method id
method id method id
"LBlort;"
method id "zap"
method id
proto id "Ljava/lang/String;"
"Ljava/lang/Object;"
Shared Constant Pool
Memory is saved via…
• minimal repetition
• implicit labeling
Size Comparison
common system libraries
(U) 21445320 — 100% (U) uncompressed jar file
(J) 10662048 — 50% (J) compressed jar file
(D) 10311972 — 48% (D) uncompressed dex file
• dirty: malloc()ed
• shared dirty
• ???
• private dirty
• application “live” dex structures
• application heap
Enter The Zygote
• nascent VM process
• fork()s on command
Enter The Zygote
Zygote Maps
Zygote heap
Maps dex file Browser
(shared dirty,
copy-on-write; (mmap()ed) Browser dex file
Home
rarely written)
Maps live code (mmap()ed) Home dex file
and heap
Browser live (mmap()ed)
core library dex (private dirty) code and heap
files
Home live code
shared from (private dirty) and heap
(mmap()ed) Zygote
shared from (private dirty)
Zygote
shared from
"live" core Zygote
libraries
(shared dirty;
read-only)
4 Kinds Of Memory
• clean (shared or private)
• common dex files (libraries)
• shared dirty
• library “live” dex structures
• private dirty
• application “live” dex structures
• application heap
GC And Sharing
embedded separated
mark bits mark bits
mark bits
object data
object data
parallel
mark bits
mark bits object data
object data
object data
mark bits
. .
. .
. .
GC And Sharing
object data
parallel
• avoids un-sharing pages
object data
mark bits
•
object data
doesn’t waste memory
object data
.
.
.
CPU Efficiency
• Intro
• Memory
• CPU
• Advice
• Conclusion
Problem: CPU Efficiency
• JNI available
• verification
• dex structures aren’t “lying”
• valid indices
• valid offsets
• optimization
• byte-swapping and padding (unnecessary on ARM)
• static linking
op_table:
Two memory reads
.word op_a
.word op_b
...
#define DISPATCH() ldrb r0, [rPC], #1 \
ldr pc, [rOP_TABLE, r0, lsl #2]
op_a: ...
DISPATCH()
op_b: ...
DISPATCH()
...
Interpreters 101
ARM assembly (cleverer)
One memory read
• Intro
• Memory
• CPU
• Advice
• Conclusion
Time Scale
• human interaction scale
• 10-30 interactions / sec
• computer scale
• run as much and as fast as possible
Get Plenty Of Rest
A well-behaved app…
Danger! Danger!
Avoid Allocation
• Intro
• Memory
• CPU
• Advice
• Conclusion
Questions?