JVM内存管理和垃圾收集

来源:http://liuxuan.info/blog/2011/04/03/jvm-memory-management-and-gc/

一.Java基本类型和类的大小

1.Java手册上的类型大小

byte:8-bit

short:16-bit

Int:32-bit

long:64-bit

char:16bitunsignedinteger

float:32-bit

double:64-bit

boolean:1-bit

2.实际存储大小(根据JVM实现而定)

Byte:16bytes

Short:16bytes

Integer:16bytes

Long:16bytes

Character:16bytes

Float:16bytes

Double:16bytes

Boolean:16bytes

Object:8bytes

二.JVM的堆结构

运行时数据区域,所有类实例和数组的内存均从此处分配,由Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

堆由两部分组成:

Eden+FromSpace+ToSpace也叫做YoungGeneration(年轻代),TenuredSpace也叫做OldGeneration(老年代)。

SurvivorSpace包括S0和S1。

PermanentSpace(方法区):JVM具有一个由所有线程共享的方法区。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码,它是在Java虚拟机启动时创建的,不包括在JVM堆内,默认为4M。

这个区域主要存放:

1.Class的信息

包名

父类的包名

类或接口

类型修饰符

父接口包名

2.其它信息

类型的常量池

属性

方法

类里的静态变量(除了常量)

一个指向ClassLoader的引用

一个指向Class类的引用

三.GC的工作流程

绝大多数情况下对象初始化被分配在Eden中(一个非常大的对象会被分配在老年代中)。

如果Eden空间占满了,会触发minorGC。MinorGC后仍然存活的对象会被复制到S0中去。这样Eden就被清空可以分配给新的对象。

又触发了一次MinorGC,S0和Eden中存活的对象被复制到S1中,并且S0和Eden被清空。在同一时刻,只有Eden和一个SurvivorSpace同时被操作。

当每次对象从Eden复制到SurvivorSpace或者从SurvivorSpace中的一个复制到另外一个,有一个计数器会自动增加值。默认情况下如果复制发生超过16次,JVM会停止复制并把他们移到老年代中去。

如果一个对象不能在Eden中被创建,它会直接被创建在老年代中。如果老年代的空间被占满会触发老年代的GC,也被称为FullGC。fullGC是一个压缩处理过程,所以它比MinorGC要慢很多。

四.GC算法

SerialCollector

大部分平台或者强制java-client默认会使用这种。YoungGeneration=SerialOldGeneration=Serial(Mark-Sweep-Compact)这种方法的缺点很明显,Stop-the-world,速度慢。服务器应用不推荐使用。

ParallelCollector

在Linuxx64上默认是这种算法,其他平台要加java-server参数。YoungGeneration=parallel,多个thread同时copyOldGeneration=Mark-Sweep-Compact=1优点:新生代回收更快。因为系统大部分时间做的GC都是新生代的,这样提高了Throughput(CPU用于非GC时间)。缺点:当运行在8G/16GServer上OldGeneration存活对象太多的时候暂停时间(PauseTime)过长。

ParallelCompactingCollector(ParallelOld)

YoungGeneration=parallelOldGeneration=parallel优点:OldGeneration上性能较ParallelCollector方式有提高。缺点:大部分Server系统OldGeneration内存占用会达到60%-80%,Compact方面开销比起ParallelCollector并没明显减少。

ConcurentMark-Sweep(CMS)Collector(low-latencycollector)

YoungGeneration=parallelOldGeneration=CMS同时不做compact操作。优点:PauseTime会降低,PauseTime敏感但CPU有空闲的场景需要建议使用策略4。缺点:CPU占用过多,CPU密集型服务器不适合。需要更大的堆空间,会造成很多碎片。

五.JVM的默认设置

1.堆(heap)即(NewGeneration和OldGeneraion之和)的设置

初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。

最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。

默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio指定。

默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio指定。

服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小,所以上面的两个参数没啥用。

-Xmn设置YoungGeneration的heap大小

-XX:MinHeapFreeRatio与-XX:MaxHeapFreeRatio设定空闲内存占总内存的比例范围,这两个参数会影响GC的频率和单次GC的耗时。-XX:NewRatio决定Young与OldGeneration的比例。Younggeneration空间越大,MinorGC频率越低,但是OldGeneration空间小了,又可能导致MajorGC频率增加。-XX:NewSize和-XX:MaxNewSize直接指定了YoungGeneration的缺省大小和最大大小。

2.非堆内存的设置

默认分配为64M

-XX:PermSize设置最小分配空间,-XX:MaxPermSize设置最大分配空间。一般把这两个数值设为相同,以减少申请内存空间的时间。

六.GC调优

参考:GC调优例子

设置Xms=Xmx=3/4物理内存,-Xmn为1/4的-Xmx值

如果是CPU密集型服务器,使用–XX:+UseParallelOldGC,否则–XX:+UseConcMarkSweepGC

新生代,Parallel/ParallelOld可设大于Xmx1/4,CMS可设小,小于Xmx1/4

经验之谈:通常情况下,JVM堆的大小应为物理内存的80%

七.Dumpheap

1.Linux下:jmap-dump:file=xxx.hprofpid,其中pid通过ps-aux命令查看

2.命令行:jstat-gcutilpidp1p2,其中p1表示每多少毫秒打印一次;p2表示一共打印几次。

输出的参数含义:

S0:Heap上的Survivorspace0段已使用空间的百分比

S1:Heap上的Survivorspace1段已使用空间的百分比

E:Heap上的Edenspace段已使用空间的百分比

O:Heap上的Oldspace段已使用空间的百分比

P:Permspace已使用空间的百分比

YGC:从程序启动到采样时发生YoungGC的次数

YGCT:YoungGC所用的时间(单位秒)

FGC:从程序启动到采样时发生FullGC的次数

FGCT:FullGC所用的时间(单位秒)

GCT:用于垃圾回收的总时间(单位秒)

jstat命令其他参数含义:

jstat-classpid:显示加载class的数量,及所占空间等信息。

jstat-compilerpid:显示VM实时编译的数量等信息。

jstat-gcpid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是younggc的次数,younggc的时间,fullgc的次数,fullgc的时间,gc的总时间。

jstat-gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推,OC是old内纯的占用量。

jstat-gcnewpid:new对象的信息。

jstat-gcnewcapacitypid:new对象的信息及其占用量。

jstat-gcoldpid:old对象的信息。

jstat-gcoldcapacitypid:old对象的信息及其占用量。

jstat-gcpermcapacitypid:perm对象的信息及其占用量。

jstat-utilpid:统计gc信息统计。

jstat-printcompilationpid:当前VM执行的信息。

3.GCLog

-Xloggc:d:\gc.log-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeStamps–addtimestamp

八.OutofMemory-java.lang.OutOfMemoryError

1.Javaheapspace

Configurationissue:-Xmx

MemoryLeak:Theexcessiveuseoffinalizers

PermGenspace:Toomanyclasses-XX:MaxPermSize

RequestedarraysizeexceedsVMlimit:Needasobigarray?

Requestbytesfor:Outofswapspace?

NativeMemoryLeak

(Nativemethod)

NativeMemoryAllocationIssue

2.PermMemoryLeak

(1)TooManyInternedString

String.intern()

ConstantStringwillbeinternedimplicitly

NoEnoughInfoprovidedbyHeapDumponInternedString

IfPermMemoryincreaseddynamically,becareful

(2)TooManyClassesorClassLoadLeak

Enlargethepermgeneration

Avoidduplicatedclassloader

3.OutofSwapSpace

Enlargetheswapspace

Systemswith4GBoframorlessrequireaminimumof2GBofswapspace

Systemswith4GBto16GBoframrequireaminimumof4GBofswapspace

ForUnixFamilyOS,usepmdumporpmap,libumemforSolaris

相关推荐