java memory tips&tricks

21
Java Memory Tips & Tricks Roger ([email protected] , [email protected] ) 06/16/2022 1 Roger, UC

Upload: rogeryi

Post on 26-Jun-2015

1.086 views

Category:

Technology


3 download

DESCRIPTION

介绍了Java基本对象(空对象,引用,数组,字串)的内存开销和一些内存分配与布局的比较特殊的现象。另外提供了一些节省内存消耗的技巧。

TRANSCRIPT

Page 1: Java Memory Tips&Tricks

04/13/2023 Roger, UC 1

Java Memory Tips & Tricks

Roger ([email protected], [email protected])

Page 2: Java Memory Tips&Tricks

04/13/2023 Roger, UC 2

大纲

• Tips– 统计数据– 基本对象大小– 内存分配和布局

• Tricks– 对象的最佳大小– 对象还是基础类型 , to be or not to be– byte , short 还是 int– 字串, char 数组还是 byte 数组– 字串和子串

Page 3: Java Memory Tips&Tricks

04/13/2023 Roger, UC 3

Java Memory

• C 通过结构体,指针,位域变量等机制,允许程序员完全控制数据结构的内存布局,能够精准地对每一个 bit 进行操作。

• Java 隐藏了内存布局的细节,不允许直接操作内存,提供垃圾回收机制。– 这些做法大大提高了系统的健壮性和开发效率,避免

了大量跟内存访问有关的错误(越界访问,悬挂指针, etc… )

Page 4: Java Memory Tips&Tricks

04/13/2023 Roger, UC 4

Cont.

• Java– 但是也为希望更精确地了解内存分配和内存布局的细

节造成了障碍…– 而了解这些细节可以帮助程序员更准确地控制内存开

销,避免多余的内存耗费,必要时甚至可以采取用时间换空间的方案来节约内存

– 在嵌入式平台如 J2ME , Android 上,节约内存仍然是一件有意义的事情

Page 5: Java Memory Tips&Tricks

04/13/2023 Roger, UC 5

度量方法• 对 Java 的内存度量基本上可以采取两种方式

– 利用 Memory Profiler– 利用 Runtime 提供的内存 API ,自己编写度量代码– 后者对于度量对象的大小会更准确一些,也是本文所

使用的方法

• 参考文章– J2ME Memory Profiling– Java Tip 130: Do you know your data size?

Page 6: Java Memory Tips&Tricks

04/13/2023 Roger, UC 6

统计数据Object Type JDK 32bits JDK 64bits WTK2.52 Simulator M8 kJVM Samsung 5230 kJVM Android 2.3/3.0

SimulatorM8 Android2.1LePhone Android2.2

BlackBerry Simulator 2.13

Object 8 16 12 4 4 16 16 16

Object Reference 4 4 4 4 4 4 4 4

Integer 16 16 16 8 8 16 16 20

Long 16 24 20 12 12 24 24 24

byte[0] 16 16 16 8 8 24 24 20

byte[1] 16 24 20 12 12 24 24 20

byte[2] 16 24 20 12 12 24 24 20

byte[3] 16 24 20 12 12 24 24 20

byte[4] 16 24 20 12 12 24 24 20

byte[5] 24 24 24 16 16 32 32 24

byte[6] 24 24 24 16 16 32 32 24

byte[7] 24 24 24 16 16 32 32 24

byte[8] 24 24 24 16 16 32 32 24

char[0] 16 16 16 8 8 24 24 20

char[1] 16 24 20 12 12 24 24 20

char[2] 16 24 20 12 12 24 24 24

char[3] 24 24 24 16 16 32 32 24

char[4] 24 24 24 16 16 32 32 28

char[5] 24 32 28 20 20 32 32 28

char[6] 24 32 28 20 20 32 32 32

char[7] 32 32 32 24 24 40 40 32

char[8] 32 32 32 24 24 40 40 36

int[0] 16 16 16 8 8 24 24 16

int[1] 16 24 20 12 12 24 24 20

int[2] 24 24 24 16 16 32 32 24

int[3] 24 32 28 20 20 32 32 28

int[4] 32 32 32 24 24 40 40 32

String[0] 40 48 40 24 24 56 56 52

String[1] 40 56 44 28 28 56 56 56

String[2] 40 56 44 28 28 56 56 60

String[3] 48 56 48 32 32 64 64 64

String[4] 48 56 48 32 32 64 64 68

String[5] 48 64 52 36 36 64 64 72

String[6] 48 64 52 36 36 64 64 72

String[7] 56 64 56 40 40 72 72 76

String[8] 56 64 56 40 40 72 72 80

Eight Bytes 16 24 44 12 12 48 48 48

Four Chars 16 24 28 12 12 32 32 32

Four Bytes and Three Integer Interlace

24 32 40 20 20 40 40 44

Page 7: Java Memory Tips&Tricks

04/13/2023 Roger, UC 7

基本对象大小• 一个 Object 的大小在不同的平台和实现上都不

一样– 32 位 JDK 是 8 bytes– 64 位 JDK 是 12 bytes– 大部分的 kJVM 上是 4 bytes– Android 上是 12 bytes

• 所有平台上,一个对象的引用都是 4 bytes

Page 8: Java Memory Tips&Tricks

04/13/2023 Roger, UC 8

Cont.

• 其它继承 Object 的类的实例的大小为一个Object 的大小加上自身的成员变量– 比如 Integer 的大小就是一个 Object 的大小加上一个

int 类型变量的大小– Long 的大小就是一个 Object 的大小加上一个 long

类型变量的大小

Page 9: Java Memory Tips&Tricks

04/13/2023 Roger, UC 9

Cont.

• 数组的大小除了数组元素本身的大小和数组的长度外,额外开销是一个 int 类型的长度值和一个对象的大小,假设一个对象的大小是 8– byte[] = 8 + 4 + 1*length– char[] = 8 + 4 + 2*length– int[] = 8 + 4 + 4*length– Object[] = 8 + 4 + 4*length

Page 10: Java Memory Tips&Tricks

04/13/2023 Roger, UC 10

Cont.

• 字串 String 的实现在各个平台上可能有差异,比较标准的实现包括 4 个成员变量– offset ( int )– count ( int )– hashCode ( int ,在一些 kJVM 实现上可能没有该成

员)– value ( char[] )

• 这意味着一个空串也可能要 40 个 bytes…– ( 8 + 4 + 4 + 4 + 16 ) 8 取整 = 40

Page 11: Java Memory Tips&Tricks

04/13/2023 Roger, UC 11

内存分配和布局• JVM 在内存分配和成员变量布局上有两个较为特

殊的现象– 内存分配的大小一般会 8 取整,除了 kJVM 是 4 取整

外– 这意味着内存分配的大小必须是

8 , 16 , 24 , 32 , etc…– 在 WTK J2ME 模拟器和 Android 上我们也看到了成员

变量地址需要 4 对齐的现象,这意味着一个 byte 类型的成员虽然实际大小只有 1 byte ,但是也要占用 4 bytes 的空间

Page 12: Java Memory Tips&Tricks

04/13/2023 Roger, UC 12

Tricks

• 一般而言,很少需要考虑用一些特殊的技巧来减少内存耗费,因为这些特殊的技巧通常会导致额外的,难以理解的,降低效率的代码。

• 除非– 运行环境的可用内存非常有限– 设计底层库的关键类,比如某个类阶层的根类,该类

的实例在系统运行时的可能存在数量非常大– 牺牲的效率在可以接受的范围

Page 13: Java Memory Tips&Tricks

04/13/2023 Roger, UC 13

对象的最佳大小• 因为 JVM 在内存大小分配上的 8 取整现象

( kJVM 是 4 取整),所以在设计一个类时,这个类的成员变量的总大小加上一个 Object 的大小最好是 8 的倍数(在 kJVM 上最好是 4 的倍数)

Page 14: Java Memory Tips&Tricks

04/13/2023 Roger, UC 14

对象还是基础类型• Java 除了基础类型,其它类型全部都是对象,它

们都必须在 Heap 上占据一个完整对象的开销• 假设我们有一个 Rectangle ,它包含

x , y , width , height 4 个成员,另外有一个类 Widget ,它需要一个矩形作为 bounds表示它的可见区域

Page 15: Java Memory Tips&Tricks

04/13/2023 Roger, UC 15

Cont.

Page 16: Java Memory Tips&Tricks

04/13/2023 Roger, UC 16

Cont.

• 上图显示了两种不同的布局,第一种是 Widget包含一个 Rectangle 类型的 bounds 成员,另外一种是 Widget 直接包含x , y , width , height 4 个 int 类型成员

• 因为没有结构体或者是 C#中所谓的 Value Class , Java 只能在这两种状况中选一个,后者耗费更少内存,但是也带来很多不便

Page 17: Java Memory Tips&Tricks

04/13/2023 Roger, UC 17

byte, short还是 int

• 有时我们会用 byte或者 short 来声明一个整数类型成员,在值不会溢出的情况下,比用 int 更省内存

• 但是如前述,这种做法在 Android或者其它存在变量地址需要 4 对齐现象的 JVM 上是无用的

• 在这类 JVM 上,我们可能用一个 int ,然后利用位操作,把它当作 4 个 bytes或者 2 个 shorts

• 把一个 int当作 32 个 boolean 的位集( BitSet)来用比较常见

Page 18: Java Memory Tips&Tricks

04/13/2023 Roger, UC 18

字串, char数组还是 byte数组

• 我们之前已经看到 Java里面一个 String 对象有很多额外的开销,有时候只持有一个 char 数组会更节约内存,甚至当字串里面大部分都是英文的情况下,可以考虑持有编码成 utf-8 的 byte 数组

• 但是因为 String 是不可变对象,通过 char 数组构造一个 String , String 的构造函数会拷贝一份而不是直接引用外部的 char 数组

• byte 数组需要额外的解码时间开销

Page 19: Java Memory Tips&Tricks

04/13/2023 Roger, UC 19

字串和子串• 两个不同的 String 指涉同一个 char 数组的不同

部分是可行的,它并不违反 String 的不可变性– 实际上 String 的 substring 就利用了这种特性,得到

的子串跟原来的字串指涉同一个 char 数组– 假设我们需要同时持有大量的字串,比如加载一个外

部的字典文件或者本地化文本资源文件– 把这些字串先拼接成一个大字串,然后用 substring

取出原来的每一个字串会更节约内存– 主要是节省了原来每一个字串都需要的一个 char 数组

对象的额外开销,拼接再取字串的做法则只需要一个char 数组

Page 20: Java Memory Tips&Tricks

04/13/2023 Roger, UC 20

各平台的测试 Apps和源码• http://pluto-hades.googlecode.com/files/Ja

vaMemory.zip

Page 21: Java Memory Tips&Tricks

04/13/2023 Roger, UC 21

The End

Thank you for your listeningYours Sincerely, Roger