ImageVerifierCode 换一换
格式:DOCX , 页数:9 ,大小:34.38KB ,
资源ID:6743610      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6743610.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(总结的内存溢出.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

总结的内存溢出.docx

1、总结的内存溢出1、JVM的内存模型从大的方面来讲,JVM的内存模型分为两大块:永久性内存(Permanent space)和堆内存(heap space)。栈内存(stack space)一般不归在JVM内存模型中,栈内存属于线程级别。每个线程都有独立的栈内存空间。 Young Gen:年轻代,包括1个Eden区和2个Survivor区,新创建的对象(大部分为短周期的对象)将进入这个区,虚拟机会频繁地对这个区进行垃圾回收。 Old Gen:年老代,当对象在Young Gen呆地足够久(经过几次的垃圾回收仍然存在)或Young Gen空间不足时,对象将进入Old Gen,由于一般是生命周期比较长

2、的对象,因此虚拟机对这块内存的回收频度会比较低,一旦回收,使用的将是一个耗时的Full GC,另外,一旦堆空间不足时,虚拟机也会尝试去回收这个区。 Perm Gen:持久代,一些常量定义和类、方法声明及其bytecode都会放在这个区。1.1 Permanent spacePermanent space是指内存的永久保存区域,主要用于存放加载的class类级对象如class本身、method、field等。它和存放类实例的Heap区域不同,GC(Garbage Coolection)不会在主程序运行期对Permanent space进行清理。如果应用中有很有class的话,且permanent

3、 space设置得比较小就有可能会出现这样的错误。Permanent space大小的设置:-XX:PermSize用于设置永久保存区域初始大小;-XX:MaxPermSize用于设置永久保存区域的最大值。1.2 Heap spaceHeap space由Old Generation和New Generation组成,Old Generation存放生命周期长久的实例对象,而新的对象实例一般放在New Generation。New Generation可再分为Eden区、Survivor区,新对象实例总是首先放在Eden区,Survivor作为Eden区和Old区的缓冲,可以向Old区转移活动

4、的对象实例。 其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1 /4。如果内存剩余不到40,JVM就会增大堆到Xmx设置的值,内存剩余超过70,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms 设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收New中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无

5、内存空间容纳新的Java对象的情况。当一个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区进行完全的

6、垃圾收集(0级) F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现out of memory错误、2、内存分配的相关参数ms/mx:定义NEW+OLD段的总尺寸,ms为JVM启动时NEW+OLD的内存大小;mx为最大可占用的NEW+OLD内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。NewSize/MaxNewSize:定义NEW段的尺寸,NewSize为JVM启动时NEW的内存大小;MaxNewSize为最大可占用的NEW内存大小。在用户生产环境上一

7、般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。PermSize/MaxPermSize:定义Perm段的尺寸,PermSize为JVM启动时Perm的内存大小;MaxPermSize为最大可占用的Perm内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。SurvivorRatio:设置Survivor空间和Eden空间的比例。NewRatio:设置Old区域与NEW区域的比例。3、GC的算法1)标记非活动对象何为非活动对象,通俗的讲,就是无引用的对象。 追踪root对象算法: 深度追踪root对象,将heap中所有被引用到的root做

8、标志,所有未被标志的对象视为非活动对象,所占用的空间视为非活动内存。 2)清理非活动对象Copy算法:方法:将内存分为两个区域(from space和to space)。所有的对象分配内存都分配到from space。在清理非活动对象阶段,把所有标志为活动的对象,copy到to space,之后清楚from space空间。然后互换from sapce和to space的身份。既原先的from space变成to sapce,原先的to space变成from space。每次清理,重复上述过程。优点:copy算法不理会非活动对象,copy数量仅仅取决为活动对象的数量。并且在copy的同时,整

9、理了heap空间,即,to space的空间使用始终是连续的,内存使用效率得到提高。 缺点:划分from space和to space,内存的使用率是12。Compaction算法:方法:在清理非活动对象阶段,删除非活动对象占用内存,并且把活动对象向heap的底部移动,直到所有的活动对象被移到heap的一侧。 优点:无须划分from sapce和to space,提高内存的使用率。并且compaction后的内存空间也是连续分配的。 缺点:该算法相对比较复杂。 如果能对这两种对象区分对象,那么会提高GC的效率。在sun jdk gc中(具体的说,是在jdk1.4之后的版本),提出了不同生命周期

10、的GC策略。 young generation:生命周期很短的对象,归为young generation。由于生命周期很短,这部分对象在gc的时候,很大部分的对象已经成为非活动对象。因此针对young generation的对象,采用copy算法,只需要将少量的存活下来的对象copy到to space。存活的对象数量越少,那么copy算法的效率越高。young generation的gc称为minor gc。经过数次minor gc,依旧存活的对象,将被移出young generation,移到tenured generation(下面将会介绍)young generation分为: eden

11、:每当对象创建的时候,总是被分配在这个区域 survivor1:copy算法中的from space survivor2:copy算法中的to sapce (备注:其中survivor1和survivor2的身份在每次minor gc后被互换)minor gc的时候,会把eden+survivor1(2)的对象copy到survivor2(1)去。tenured generation: 生命周期较常的对象,归入到tenured generation。一般是经过多次minor gc,还 依旧存活的对象,将移入到tenured generation。(当然,在minor gc中如果存活的对象的超过

12、survivor的容量,放不下的对象会直接移入到tenured generation)。tenured generation的gc称为major gc,就是通常说的full gc。 采用compactiion算法。由于tenured generaion区域比较大,而且通常对象生命周期都比较常,compaction需要一定时间。所以这部分的gc时间比较长。 minor gc可能引发full gc。当edenfrom space的空间大于tenured generation区的剩余空间时,会引发full gc。这是悲观算法,要确保edenfrom space的对象如果都存活,必须有足够的tenur

13、ed generation空间存放这些对象。 Permanet Generation: 该区域比较稳定,主要用于存放classloader信息,比如类信息和method信息。对于spring hibernate这些需要动态类型支持的框架,这个区域需要足够的空间。这部分内容相对比较理论,可以结合jstat,jmap等命令(当然也可以使用jconsole,jprofile,gciewer等工具),观察jdk gc的情况。4、jdk自带的jps jmap jstat 等工具jps:相当于linux下的ps,列出所有java相关线程的pid等信息example:$ jps18861 Bootstrap

14、1418 Jpsjmap:显示java进程内存使用的相关信息jmap pid 打印内存使用的摘要信息jmap -histopid mem.txt 打印比较简单的各个有多少个对象占了多少内存的信息,一般重定向的文件jmap -dump:format=b,file= mem.dat pid 将内存使用的详细情况输出到em.dat 文件jmap -dump:live,format=b,file=heap.bin analyze heap将二进制的heap dump文件解析成human-readable的信息,自然是需要专业工具的帮助,这里推荐Memory Analyzer 。用jhat命令可以参看

15、jhat -port 7000 mem.dat在浏览器中访问:http:/10.5.22.65:7000/ 查看详细信息jstat:显示java虚拟机的一些统计信息jstat -选项 pid 间隔显示时间 显示次数jstat -gc 18861 250 10jstat -gccapacity 18861 250 10jstat -gcnew 18861 250 10jstat -gcnewcapacity 18861 250 10jstat -gcold 18861 250 10jstat -gcutil pid 1000 200表示每1秒打印一次,共200次S0 Heap上的 Survivo

16、r space 0 区已使用空间的百分比S1 Heap上的 Survivor space 1 区已使用空间的百分比E Heap上的 Eden space 区已使用空间的百分比 Heap上的 Old space 区已使用空间的百分比P Perm space 区已使用空间的百分比YGC 从应用程序启动到采样时发生 Young GC 的次数YGCT 从应用程序启动到采样时 Young GC 所用的时间(单位秒)FGC 从应用程序启动到采样时发生 Full GC 的次数FGCT 从应用程序启动到采样时 Full GC 所用的时间(单位秒)GCT 从应用程序启动到采样时用于垃圾回收的总时间(单位秒) 调

17、试流程内存泄漏一般都是有一定特征的,任何代码和数据都要占用内存,简单总结内存泄漏的特征是内存占用不可控制,GC不可回收。追踪内存使用量的曲线发现一些特征,在估计虚拟机即将崩溃时,使用 jmap -histopid mem.txt 发现相关内存泄漏的对象占用非常打比例的内存空间,然后很容易猜测问题大概的位置,一下子就解决了。对于内存泄露的压力测试也开始实实在在的做起来。经过这次问题的定位和解决以后,大致觉得对于一个大用户量应用要放心的话,那么需要做这么几步。1.在GC输出的环境下,大压力下做多天的测试。(可以在 JAVA_OPTS增加-verbose:gc -XX:+PrintGCDetails

18、 -XX:+HeapDumpOnOutOfMemoryError)2.检查GC输出日志来判断是否有内存泄露。(这部分后面有详细的实例说明)3.如果出现内存泄露问题,则使用jprofiler等工具来排查内存泄露点(之所以不一开始使用,因为jprofiler等工具对于压力测试有影响,使得大压力无法上去,也使问题不那么容易暴露)4.解决问题,并在重复2步骤。(这里的内存泄露问题就是在以前blog写过的jdk的concurrent包内LinkedBlockingQueue的poll方法存在比较严重的内存泄露,调用频率越高,内存泄露的越厉害)两次压力测试都差不多都是两天,测试方案如下:开始50个并发,每

19、个并发每次请求完毕后休息0.1秒,10分钟后增长50个并发,按此规律增长到500并发。先说一下日志输出的结构:(1.6和1.5略微有一些不同,只是1.6对于时间统计更加细致)GC : - , secs - , secsGC收集器的名称 新生代在GC前占用的内存 新生代在GC后占用的内存 新生代局部收集时jvm暂停处理的时间 JVM Heap 在GC前占用的内存 JVM Heap 在GC后占用的内存 GC过程中jvm暂停处理的总时间Jdk1.5 log:启动时GC输出:GC DefNew: 209792K-4417K(235968K), 0.0201630 secs 246722K-41347K

20、(498112K), 0.0204050 secsGC DefNew: 214209K-4381K(235968K), 0.0139200 secs 251139K-41312K(498112K), 0.0141190 secs一句输出:新生代回收前209792K,回收后4417K,回收数量205375K,Heap总量回收前246722K回收后41347K,回收总量205375K。这就表示100%的收回,没有任何新生代的对象被提升到中生代或者永久区(名字说的不一定准确,只是表达意思)。第二句输出:按照分析也就只是有1K内容被提升到中生代。运行一段时间后:GC DefNew: 210686K-9

21、79K(235968K), 0.0257140 secs 278070K-68379K(498244K), 0.0261820 secsGC DefNew: 210771K-1129K(235968K), 0.0275160 secs 278171K-68544K(498244K), 0.0280050 secs第一句输出:新生代回收前210686K,回收后979K,回收数量209707K,Heap总量回收前278070K回收后68379K,回收总量209691K。这就表示有16k没有被回收。第二句输出:新生代回收前210771K,回收后1129K,回收数量209642K,Heap总量回收前2

22、78171K回收后68544K,回收总量209627K。这就表示有15k没有被回收。比较一下启动时与现在的新生代占用内存情况和Heap使用情况发现Heap的使用增长很明显,新生代没有增长,而Heap使用总量增长了27M,这就表明可能存在内存泄露,虽然每一次泄露的字节数很少,但是频率很高,大部分泄露的对象都被升级到了中生代或者持久代。又一段时间后:GC DefNew: 211554K-1913K(235968K), 0.0461130 secs 350102K-140481K(648160K), 0.0469790 secsGC DefNew: 211707K-2327K(235968K), 0

23、.0546170 secs 350275K-140921K(648160K), 0.0555070 secs第一句输出:新生代回收前211554K,回收后1913K,回收数量209641K,Heap总量回收前350102K回收后140481K,回收总量209621K。这就表示有20k没有被回收。分析到这里就可以看出每一次泄露的内存只有10几K,但是在大压力长时间的测试下,内存泄露还是很明显的,此时Heap已经增长到了140M,较启动时已经增长了100M。同时GC占用的时间越来越长。后续的现象:后续观察日志会发现,Full GC的频率越来越高,收集所花费时间也是越来越长。(Full GC定期会执

24、行,同时局部回收不能满足分配需求的情况下也会执行)。Full GC Tenured: 786431K-786431K(786432K), 3.4882390 secs 1022399K-1022399K(1022400K), Perm : 36711K-36711K(98304K), 3.4887920 secsjava.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid7720.hprof . 出现这个语句表示内存真的被消耗完了。Jdk1.6 log:启动时GC的输出:GC PSYoungGen: 221697K-31

25、960K(229376K) 225788K-36051K(491520K), 0.0521830 secs Times: user=0.26 sys=0.05, real=0.05 secs GC PSYoungGen: 228568K-32752K(229376K) 232659K-37036K(491520K), 0.0408620 secs Times: user=0.21 sys=0.02, real=0.04 secs第一句输出:新生代回收前221697K,回收后31960K,回收数量189737K,Heap总量回收前225788K回收后36051K,回收总量189737K。100%

26、被回收。运行一段时间后输出:GC PSYoungGen: 258944K-2536K(259328K) 853863K-598135K(997888K), 0.0471620 secs Times: user=0.15 sys=0.00, real=0.05 secs GC PSYoungGen: 259048K-2624K(259328K) 854647K-598907K(997888K), 0.0462980 secs Times: user=0.16 sys=0.02, real=0.04 secs第一句输出:新生代回收前258944K,回收后2536K,回收数量256408K,Heap

27、总量回收前853863K回收后598135K,回收总量255728K。680K没有被回收,但这并不意味着就会产生内存泄露。同时可以看出GC回收时间并没有增加。在运行一段时间后输出:GC PSYoungGen: 258904K-2488K(259264K) 969663K-713923K(1045696K), 0.0485140 secs Times: user=0.16 sys=0.01, real=0.04 secs GC PSYoungGen: 258872K-2448K(259328K) 970307K-714563K(1045760K), 0.0473770 secs Times: u

28、ser=0.16 sys=0.01, real=0.05 secs第一句输出:新生代回收前258904K,回收后2488K,回收数量256416K,Heap总量回收前969663K回收后713923K,回收总量255740K。676K没有被回收,同时总的Heap也有所增加。此时看起来好像和1.5的状况一样。但是查看了一下Full GC的执行还是400-500次GC执行一次,因此继续观察。运行一天多以后输出:GC PSYoungGen: 257016K-3304K(257984K) 1019358K-766310K(1044416K), 0.0567120 secs Times: user=0.

29、18 sys=0.01, real=0.06 secs GC PSYoungGen: 257128K-2920K(258112K) 1020134K-766622K(1044544K), 0.0549570 secs Times: user=0.19 sys=0.00, real=0.05 secs可以发现Heap增长趋缓。运行两天以后输出:GC PSYoungGen: 256936K-3584K(257792K) 859561K-606969K(1044224K), 0.0565910 secs Times: user=0.18 sys=0.01, real=0.06 secs GC PSY

30、oungGen: 256960K-3368K(257728K) 860345K-607445K(1044160K), 0.0553780 secs Times: user=0.18 sys=0.01, real=0.06 secs发现Heap反而减少了,此时可以对内存泄露问题作初步排除了。(其实在jdk1.6环境下用jprofiler来观察,对于concurrent那个内存泄露点的跟踪发现,内存的确还是会不断增长的,不过在一段时间后还是有回收,因此也就可以部分解释前面出现的情况)总结:对于GC输出的观察需要分两个维度来看。一个是纵向比较,也就是一次回收对于内存变化的观察。一个是横向比较,对于长时间内存分配占用情况的比较,这部分比较需要较长时间的观察,不能仅仅凭短时间的几个抽样比较,因为对于抽样来说,Full GC前后的区别,运行时长的区别,资源瞬时占用的区别都会影响判断。同时要结合Full GC发生的时间周期,每一次GC收集所耗费的时间作为辅助判断标准。顺便说一下,Heap的 YoungGen,OldGen,PermGen的设置也是需要注意的,并不是越大越好,越大执行收集的时间越久,但是可能执行

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1