没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
java.lang.OutOfMemoryError
的
8
种
典
型
案
例
笔者在工作中碰到过各种各样的 java.lang.OutOfMemoryError ,其中最常见的可以归为以下八种类型。
本手册阐述了各种内存溢出错误的形成原因,并提供了可测试这种错误的示例代码,以及解决方案。内容都来源于笔
者的一线开发和实践经验。
版本:V1.0
校对日期:2017年10月09日
目录:
OutOfMemoryError系列(1):Javaheapspace
OutOfMemoryError系列(2):GCoverheadlimitexceeded
OutOfMemoryError系列(3):P ermgenspace
OutOfMemoryError系列(4):Met aspace
OutOfMemoryError系列(5):Unabletocreatenewnativethread
OutOfMemoryError系列(6):Outofswapspace?
OutOfMemoryError系列(7):RequestedarraysizeexceedsV Mli mit
OutOfMemoryError系列(8):K illprocessor sacrificechild
GitHub版本在这里:https://github.com/cncounter/outof memoryerror
CSDN博客版本在这里:http://blog.csdn.net/renfuf ei/article/category/5884735
原文作者:NikitaSalnikovTarnovskiPlumbrCoFounderandVPofEngineering
原文链接:https://plumbr.eu/outofm emoryerror
翻译日期:2017年9月21日
翻译人员:铁锚:http://blog.csdn.net/renfufei
OutOfMemoryError
系
列
(
1
)
:Javaheapspace
JVM限制了Java程序的最大内存使用量,由JVM的启动参数决定。而Java程序的内存被划分为两大部分:堆内存
(Heapspace)和永久代(PermanentGeneration,简称Permgen),如下图所示:
这两块内存区域的最大尺寸,由JVM启动参数 ‐Xmx 和 ‐XX:MaxPermSize 指定.如果没有明确指定,则根据平台类
型(OS版本+JVM版本)和物理内存的大小来确定。
假如在创建新的对象时,堆内存中的空间不足以存放新创建的对象,就会引发 java.lang.OutOfMemoryError:Java
heapspace 错误。
不管机器上还没有空闲的物理内存,只要堆内存使用量达到最大内存限制,就会抛出 java.lang.OutOfMemoryError:
Javaheapspace 错误。
原
因
分
析
产生 java.lang.OutOfMemoryError:Javaheapspace 错误的原因,很多时候,就类似于将XXL号的对象,往S号
的Javaheapspace里面塞。其实清楚了原因,就很容易解决对不对?只要增加堆内存的大小,程序就能正常运行.
另外还有一些比较复杂的情况,主要是由代码问题导致的:
超
出
预
期
的
访
问
量
/
数
据
量
。应用系统设计时,一般是有“容量”定义的,部署这么多机器,用来处理一定量的数
据/业务。如果访问量突然飙升,超过预期的阈值,类似于时间坐标系中针尖形状的图谱,那么在峰值所在的时
间段,程序很可能就会卡死、并触发java.lang.OutOfMemoryError:Javaheapspace错误。
内
存
泄
露
(Memoryleak).这也是一种经常出现的情形。由于代码中的某些错误,导致系统占用的内存越来越
多.如果某个方法/某段代码存在内存泄漏,每执行一次,就会(有更多的垃圾对象)占用更多的内存.随着运行
时间的推移,泄漏的对象耗光了堆中的所有内存,那么java.lang.OutOfMemoryError:Javaheapspace错误就
爆发了。
示
例
一个
非
常
简
单
的
示
例
以下代码非常简单,程序试图分配容量为2M的int数组.如果指定启动参数 ‐Xmx12m ,那么就会发生
java.lang.OutOfMemoryError:Javaheapspace 错误。而只要将参数稍微修改一下,变成 ‐Xmx13m ,错误就不再
发生。
publicclassOOM{
staticfinalintSIZE=2*1024*1024;
publicstaticvoidmain(String[]a){
int[]i=newint[SIZE];
}
}
内
存
泄
漏
示
例
这个示例更真实一些。在Java中,创建一个新对象时,例如 Integernum=newInteger(5); ,并不需要手动分配
内存。因为JVM自动封装并处理了内存分配.在程序执行过程中,JVM会在必要时检查内存中还有哪些对象仍在使
用,而不再使用的那些对象则会被丢弃,并将其占用的内存回收和重用。这个过程称为垃圾收集.JVM中负责垃圾回
收的模块叫做垃圾收集器(GC)。
Java的自动内存管理依赖GC,GC会一遍又一遍地扫描内存区域,将不使用的对象删除.简单来说,Java
中
的
内
存
泄
漏
,
就
是
那
些
逻辑
上不
再
使
用
的
对
象
,
却
没
有
被
垃圾
收
集
程
序
给
干
掉
.从而导致垃圾对象继续占用堆内存中,逐
渐堆积,最后产生java.lang.OutOfMemoryError:Javaheapspace错误。
很容易写个BUG程序,来模拟内存泄漏:
importjava.util.*;
publicclassKeylessEntry{
staticclassKey{
Integerid;
Key(Integerid){
this.id=id;
}
@Override
publicinthashCode(){
returnid.hashCode();
}
}
publicstaticvoidmain(String[]args){
Mapm=newHashMap();
while(true){
for(inti=0;i<10000;i++){
if(!m.containsKey(newKey(i))){
m.put(newKey(i),"Number:"+i);
}
}
System.out.println("m.size()="+m.size());
}
}
}
粗略一看,可能觉得没什么问题,因为这最多缓存10000个元素嘛!但仔细审查就会发现, Key 这个类只重写了
hashCode() 方法,却没有重写 equals() 方法,于是就会一直往HashMap中添加更多的Key。
请参考:Java中hashCode与equals方法的约定及重写原则
随着时间推移,“cached” 的对象会越来越多.当泄漏的对象占满了所有的堆内存,GC又清理不了,就会抛出
java.lang.OutOfMemoryError:Javaheapspace错误。
解决办法很简单,在 Key 类中恰当地实现 equals() 方法即可:
@Override
publicbooleanequals(Objecto){
booleanresponse=false;
if(oinstanceofKey){
response=(((Key)o).id).equals(this.id);
}
returnresponse;
}
说实话,在寻找真正的内存泄漏原因时,你可能会死掉很多很多的脑细胞。
一个
SpringMVC
中
的
场
景
译者曾经碰到过这样一种场景:
为了轻易地兼容从Struts2迁移到SpringMVC的代码,在Controller中直接获取request.
所以在 ControllerBase 类中通过 ThreadLocal 缓存了当前线程所持有的request对象:
publicabstractclassControllerBase{
privatestaticThreadLocal<HttpServletRequest>requestThreadLocal=new
ThreadLocal<HttpServletRequest>();
publicstaticHttpServletRequestgetRequest(){
returnrequestThreadLocal.get();
}
publicstaticvoidsetRequest(HttpServletRequestrequest){
if(null==request){
requestThreadLocal.remove();
return;
}
requestThreadLocal.set(request);
}
}
然后在SpringMVC的拦截器(Interceptor)实现类中,在 preHandle 方法里,将request对象保存到T hreadLocal中:
/**
*登录拦截器
*/
publicclassLoginCheckInterceptorimplementsHandlerInterceptor{
privateList<String>excludeList=newArrayList<String>();
publicvoidsetExcludeList(List<String>excludeList){
this.excludeList=excludeList;
}
privatebooleanvalidURI(HttpServletRequestrequest){
//如果在排除列表中
Stringuri=request.getRequestURI();
Iterator<String>iterator=excludeList.iterator();
while(iterator.hasNext()){
StringexURI=iterator.next();
if(null!=exURI&&uri.contains(exURI)){
returntrue;
}
}
//可以进行登录和权限之类的判断
LoginUseruser=ControllerBase.getLoginUser(request);
if(null!=user){
returntrue;
}
//未登录,不允许
returnfalse;
}
privatevoidinitRequestThreadLocal(HttpServletRequestrequest){
ControllerBase.setRequest(request);
request.setAttribute("basePath",ControllerBase.basePathLessSlash(request));
}
privatevoidremoveRequestThreadLocal(){
ControllerBase.setRequest(null);
}
@Override
publicbooleanpreHandle(HttpServletRequestrequest,
HttpServletResponseresponse,Objecthandler)throwsException{
initRequestThreadLocal(request);
//如果不允许操作,则返回false即可
if(false==validURI(request)){
//此处抛出异常,允许进行异常统一处理
thrownewNeedLoginException();
}
returntrue;
}
@Override
publicvoidpostHandle(HttpServletRequestrequest,
HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)
throwsException{
removeRequestThreadLocal();
剩余25页未读,继续阅读
资源评论
- zj1705032019-04-04非常详细,是非常好的教程
CcccFz
- 粉丝: 0
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功