设为首页 加入收藏

TOP

Java内存溢出相关问题(一)
2014-11-24 07:54:02 来源: 作者: 【 】 浏览:3
Tags:Java 内存 溢出 相关 问题

一、内存溢出类型


1、java.lang.OutOfMemoryError: PermGen space


JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。


2、java.lang.OutOfMemoryError: Java heap space


第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。


注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。


垃圾回收GC的角色


JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:


当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。


根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。


为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收,


一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。


二、JVM内存区域组成


简单的说java中的堆和栈


java把内存分两种:一种是栈内存,另一种是堆内存


1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;


2。堆内存用来存放由new创建的对象和数组


在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理


堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;


栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性。


java堆分为三个区:New、Old和Permanent


GC有两个线程:


新创建的对象被分配到New区,当该区被填满时会被GC辅助线程移到Old区,当Old区也填满了会触发GC主线程遍历堆内存里的所有对象。Old区的大小等于Xmx减去-Xmn


java栈存放


栈调整:参数有+UseDefaultStackSize -Xss256K,表示每个线程可申请256k的栈空间


每个线程都有他自己的Stack


三、JVM如何设置虚拟内存


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


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


提示:JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。


默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。


提示:假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。


简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,


这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了


提示:注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。


提示:设置NewSize、MaxNewSize相等,"new"的大小最好不要大于"old"的一半,原因是old区如果不够大会频繁的触发"主" GC ,大大降低了性能


JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;


由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。


解决方法:手动设置Heap size


修改TOMCAT_HOME/bin/catalina.bat


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


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


四、性能检查工具使用


定位内存泄漏:


JProfiler工具主要用于检查和跟踪系统(限于Java开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。


1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;


2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;


3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。


因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生,通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实是使用了大量内存导致out of memory,这时应继续跟踪看接下来是否会有下降,


如果一直居高不下这肯定就因为程序的原因导致内存泄漏。


五、不健壮代码的特征及解决办法


1、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。


对于仍然有指针指向的实例,jvm就不会回收该资源,因为垃圾回收会将值为null的对象作为垃圾,提高GC回收机制效率;


2、我们的程序里不可避免大量使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域;


String str = "aaa";


String str2 = "bbb";


String str3 = str + str2;//假如执行此次之后str ,str2以后再不被调用,那它就会被放在内存中等待Java的gc去回收,程序内过多的出现这样的情况就会报上面的那个错误,建议在使用字符串时能使用Strin

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Linux与Windows控制CPU使用率曲线 下一篇Android warning解决办法集锦

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·HyperText Transfer (2025-12-26 07:20:48)
·半小时搞懂 HTTP、HT (2025-12-26 07:20:42)
·CPython是什么?PyPy (2025-12-26 06:50:09)
·Python|如何安装seab (2025-12-26 06:50:06)
·python要学习数据分 (2025-12-26 06:50:03)