淘先锋技术网

首页 1 2 3 4 5 6 7

一点小经验仅供参考:

1)堆

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

堆由两部分组成:

其中eden+fromspace+tospace也叫年轻代(young),oldspace叫旧生代.

其中还有S1,S0(在JDK的自带工具输出中会看到),分别指的是Survivorspace,存放每次垃圾回收后存活的对象.

OldGeneration,主要存放应用程序中生命周期长的存活对象

垃圾回收主要是对YoungGeneration块和OldGeneration块内存进行回收,YG用来放新产生的对象,经过几次回收还没回收掉的对象往OG中移动,

对YG进行垃圾回收又叫做MinorGC,对OG垃圾回收叫MajorGC,两块内存回收互不干涉

2)非堆内存

JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。

除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。

PermanentGeneration(图中的PermanentSpace)存放JVM自己的反射对象,比如类对象和方法对象

3)回收算法和过程

JVM采用一种分代回收(generationalcollection)的策略,用较高的频率对年轻的对象(younggeneration)进行扫描和回收,这种叫做minorcollection,而对老对象(oldgeneration)的检查回收频率要低很多,称为majorcollection。这样就不需要每次GC都将内存中所有对象都检查一遍。

当一个URL被访问时,内存申请过程如下:

A.JVM会试图为相关Java对象在Eden中初始化一块内存区域

B.当Eden空间足够时,内存申请结束。否则到下一步

C.JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区

D.Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区

E.当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)

F.完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”outofmemory错误”

对象衰老的过程

younggeneration的内存,由一块Eden(伊甸园,有意思)和两块SurvivorSpace(1.4文档中称为semi-space)构成。新创建的对象的内存都分配自eden。两块SurvivorSpace总有会一块是空闲的,用作copyingcollection的目标空间。Minorcollection的过程就是将eden和在用survivorspace中的活对象copy到空闲survivorspace中。所谓survivor,也就是大部分对象在伊甸园出生后,根本活不过一次GC。对象在younggeneration里经历了一定次数的minorcollection后,年纪大了,就会被移到oldgeneration中,称为tenuring。(是否仅当survivorspace不足的时候才会将老对象tenuring?目前资料中没有找到描述)

剩余内存空间不足会触发GC,如eden空间不够了就要进行minorcollection,oldgeneration空间不够要进行majorcollection,permanentgeneration空间不足会引发fullGC。

4接下来这部分讲解的是TOMCAT或者其他服务器出现如下错误时的分析:

1、首先是:java.lang.OutOfMemoryError:Javaheapspace

解释:

Heapsize设置

JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heapsize的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn-Xms-Xmx等选项可进行设置。Heapsize的大小是YoungGeneration和TenuredGeneraion之和。

提示:在JVM中如果98%的时间是用于GC且可用的Heapsize不足2%的时候将抛出此异常信息。

提示:HeapSize最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。

解决方法:

手动设置Heapsize

修改TOMCAT_HOME/bin/catalina.bat,在“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:

Java代码

setJAVA_OPTS=%JAVA_OPTS%-server-Xms800m-Xmx800m-XX:MaxNewSize=256m

setJAVA_OPTS=%JAVA_OPTS%-server-Xms800m-Xmx800m-XX:MaxNewSize=256m

或修改catalina.sh

在“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:

JAVA_OPTS="$JAVA_OPTS-server-Xms800m-Xmx800m-XX:MaxNewSize=256m"

2、其次是:java.lang.OutOfMemoryError:PermGenspace

原因:

PermGenspace的全称是PermanentGenerationspace,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGenspace中,它和存放类实例(Instance)的Heap区域不同,GC(GarbageCollection)不会在主程序运行期对PermGenspace进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGenspace错误,这种错误常见在web服务器对JSP进行precompile的时候。如果你的WEBAPP下都用了大量的第三方jar,其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。

解决方法:

1.手动设置MaxPermSize大小

修改TOMCAT_HOME/bin/catalina.bat(Linux下为catalina.sh),在Java代码

“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:

setJAVA_OPTS=%JAVA_OPTS%-server-XX:PermSize=128M-XX:MaxPermSize=512m

“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:

setJAVA_OPTS=%JAVA_OPTS%-server-XX:PermSize=128M-XX:MaxPermSize=512m

catalina.sh下为:

Java代码

JAVA_OPTS="$JAVA_OPTS-server-XX:PermSize=128M-XX:MaxPermSize=512m"

JAVA_OPTS="$JAVA_OPTS-server-XX:PermSize=128M-XX:MaxPermSize=512m"

JVM的默认设置

堆(heap)(NewsGeneration和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空间越大,minorcollection频率越低,但是oldgeneration空间小了,又可能导致majorcollection频率增加。-XX:NewSize和-XX:MaxNewSize直接指定了younggeneration的缺省大小和最大大小。

非堆内存的设置

默认分配为64M

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

再讲解和笔记下,JDK下的一些相关看内存管理工具的使用:

查看jvm内存状态:

jstat-gcutilpid100020

异常情况的例子

jstat-gcutilpid100020

S0S1EOPYGCYGCTFGCFGCTGCT

0.000.0099.9982.5153.1124091.205101177250.3937251.598

0.000.0083.4282.5553.1024091.205101187252.6507253.855

0.000.0056.0682.4653.1024101.205101207254.4677255.672

0.000.0032.1182.5553.1024111.205101217256.6737257.877

0.000.0099.9982.5553.1024121.205101237257.0267258.231

0.000.0076.0082.5053.1024121.205101247259.2417260.446

这个数据显示FullGC频繁发生。

正常情况的例子

S0S1EOPYGCYGCTFGCFGCTGCT

0.000.000.2455.3999.601710.6671339393.364394.031

0.000.000.2455.3999.601710.6671339393.364394.031

0.000.000.2455.3999.601710.6671339393.364394.031

0.000.000.2455.3999.601710.6671339393.364394.031

0.000.000.2455.3999.601710.6671339393.364394.031

0.000.000.2455.3999.601710.6671339393.364394.031

参数含义:

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

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

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

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

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

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

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

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

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

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

2Dump出内存

2.1找出要dump的线程pid

在Linux下,使用ps–aux

2.2Dump出内存使用详情

可以通过命令:

jmap-dump:file=a.hprofpid

例如:jmap-heap2343,可以看到

AttachingtoprocessID2343,pleasewait...

Debuggerattachedsuccessfully.

Servercompilerdetected.

JVMversionis11.0-b16

usingthread-localobjectallocation.

ParallelGCwith8thread(s)

HeapConfiguration:

MinHeapFreeRatio=40

MaxHeapFreeRatio=70

MaxHeapSize=4294967296(4096.0MB)

NewSize=2686976(2.5625MB)

MaxNewSize=-65536(-0.0625MB)

OldSize=5439488(5.1875MB)

NewRatio=2(YG,OG大小比为1:2)

SurvivorRatio=8

PermSize=21757952(20.75MB)

MaxPermSize=268435456(256.0MB)

HeapUsage:

PSYoungGeneration

EdenSpace:

capacity=1260060672(1201.6875MB)

used=64868288(61.86322021484375MB)

free=1195192384(1139.8242797851562MB)

5.148028935546367%used

FromSpace:

capacity=85524480(81.5625MB)

used=59457648(56.70323181152344MB)

free=26066832(24.859268188476562MB)

69.52120375359195%used

ToSpace:

capacity=85852160(81.875MB)

used=0(0.0MB)

free=85852160(81.875MB)

0.0%used

~~~~~~~~~~~~~~~~~~~~~~~~~~这三块为上面所说的YG大小和使用情况

PSOldGeneration

capacity=2291138560(2185.0MB)

used=1747845928(1666.8757705688477MB)

free=543292632(518.1242294311523MB)

76.28722062099989%used

~~~~~~~~~~~~~~~~~~~~~~~~~~OG大小和使用情况

PSPermGeneration

capacity=108265472(103.25MB)

used=107650712(102.6637191772461MB)

free=614760(0.5862808227539062MB)

99.43217353728436%used

jstat

jstat是vm的状态监控工具,监控的内容有类加载、运行时编译及GC。

使用时,需加上查看进程的进程id,和所选参数。以下详细介绍各个参数的意义。

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执行的信息。

除了以上一个参数外,还可以同时加上两个数字,如:jstat-printcompilation30242506是每250毫秒打印一次,一共打印6次,还可以加上-h3每三行显示一下标题。

例子:

jstat-gcutilpid100020

S0S1EOPYGCYGCTFGCFGCTGCT

47.490.0064.8246.0847.69208222058.6316822.7342081.365

0.0037.9138.5746.1347.69208232058.6916822.7342081.425这里发生了一次YGGC,也就是MinorGC,耗时0.06s

46.690.0015.1946.1847.69208242058.7766822.7342081.510

46.690.0074.5946.1847.69208242058.7766822.7342081.510

0.0040.2919.9546.2447.69208252058.8486822.7342081.582

MajorGC平均时间:22.734/68=0.334秒

MinorGC平均时间:2058.691/20823=0.099秒