一、内存溢出类型
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
去回收
,
程序内过多的出现这样的情况就会报上面的那个错误
,
建议在使用字符串时能使用
StringBuffer
就不要用
String,
这样可以省不少开销;
3
、尽量少用静态变量,因为静态变量是全局的,
GC
不会回收的;
4
、避免集中创建对象尤其是大对象,
JVM
会突然需要大量内存,这时必然会触发
GC
优化系统内存环境;显示的声明数组空间,而且申请数量还极大。
这是一个案例想定供大家警戒
使用
jspsmartUpload
作文件上传
,
运行过程中经常出现
java.outofMemoryError
的错误,
检查之后发现问题:组件里的代码
m_totalBytes = m_request.getContentLength();
m_binArray = new byte[m_totalBytes];
问题原因是
totalBytes
这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。解决办法只能换一种更合适的办法,至少是不会引发
outofMemoryError
的方式解决。参考:
http://bbs.xml.org.cn/blog/more.asp?name=hongrui&id=3747
5
、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。
6
、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用
hashtable
,
vector
创建一组对象容器,然后从容器中去取那些对象,而不用每次
new
之后又丢弃
7
、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成
Out Of Memory Error
的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。
相关推荐
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。
相对于其他编程语言而言,java较为简单,例如:java不再支持多继承,C++是支持多继承的,多继承比较复杂,C++中有指针,java中屏蔽了指针的概念,避免了绝大部分的指针越界和内存泄露的问题,这里说明一下,java语言...
Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。