java 内存溢出 能不能捕获_OutOfMemoryError 到底能不能被捕获?

感觉中,OutOfMemeryError(内存溢出错误) 是jvm抛出的异常,是不能被捕获的。

直到工作中真的遇到OOM异常,而且tomcat服务还一直对外提供服务。

那么问题来了:

1. OOM 到底能不能被捕获?

2. jvm抛出OOM后,是否就会立即停止运行呢?

3. jvm什么时候会抛出OOM异常?

先来个例子:

本例子将会一一体现如上问题:(最好设置jvm最大内存如: -Xmx2m -Xms2m)

public classOOMCatchTest {/*** 可以看作是一个消息队列, 作为 Producer 与 Consumer 的通信桥梁

* 其实此处存在并发写的问题,不过不是本文的重点,暂且忽略*/

private static volatile List userWaitingList = new ArrayList<>();private AtomicInteger uidCenter = new AtomicInteger(0);//随机数生成源

private final String rndSource = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";public static void main(String[] args) throwsIOException {

OOMCatchTest oomCatchTest= newOOMCatchTest();

Thread producer= new Thread(newRunnable() {

@Overridepublic voidrun() {

System.out.println(System.currentTimeMillis()+ ": start producer.");

oomCatchTest.productUserObj();

System.out.println(System.currentTimeMillis()+ ": end producer.");

}

});

producer.setName("producer-1");

producer.start();

Thread consumer= new Thread(() ->{

System.out.println(System.currentTimeMillis()+ ": start consumer.");try{

oomCatchTest.consumeUserObj();

}catch(Throwable e) {

System.out.println("consumer caught exception: " +e.getMessage());

e.printStackTrace();

}

System.out.println(System.currentTimeMillis()+ ": end consumer.");

});

consumer.setName("consumer-1");

consumer.start();

System.out.println("over the main");

}//生产者

public voidproductUserObj() {

Random rnd= newRandom();

OOMCatchTest oomTest= newOOMCatchTest();//可作开关

boolean startProduce = true;try{while(startProduce) {

UserObj userTemp= newUserObj();

userTemp.setAddress(oomTest.generateRandomStr(20));

userTemp.setAge(rnd.nextInt(100));

userTemp.setUid(oomTest.generateUid());

userTemp.setName(oomTest.generateRandomStr(10));//此处展示 ArrayList 导致的抛出OOM类型

userWaitingList.add(userTemp);

System.out.println("produce:" +userTemp);

}

}//此处可捕获 OOM

catch(Throwable e) {//模拟一个服务提供者,做死循环

System.out.println("An Exception: "

+ e.getClass().getCanonicalName() + " " +e.getMessage()+ " occour..., cur uid:" +oomTest.uidCenter);int j = 0;//此处运行代表 OOM 并未终止jvm

while (j++ < 1000) {try{

Thread.sleep(1000);

System.out.println("producer oom, wait: " +j);

}catch(InterruptedException e1) {

e1.printStackTrace();

}

}//如果打印栈桢,只会更增加内存消耗,从而导致线程异常退出//e.printStackTrace();

}

}//消费者

public voidconsumeUserObj() {//可做开关

boolean startConsume = true;while(startConsume) {//做空等等

while(userWaitingList.isEmpty()) {

Thread.yield();

}while(userWaitingList.iterator().hasNext()) {try{//do sth

Thread.sleep(50);

}catch(InterruptedException e) {

e.printStackTrace();

}

UserObj obj=userWaitingList.iterator().next();

System.out.println("consume user:" +obj);

userWaitingList.remove(obj);

}

}

}public String generateRandomStr(intdigit) {

StringBuilder sb= newStringBuilder();int len =rndSource.length();

Random random= newRandom();for(int i = 0; i < digit; i++) {

sb.append(rndSource.charAt(random.nextInt(len)));

}returnsb.toString();

}publicInteger generateUid() {returnuidCenter.incrementAndGet();

}static classUserObj {privateInteger uid;privateString name;privateInteger age;privateString address;publicInteger getUid() {returnuid;

}public voidsetUid(Integer uid) {this.uid =uid;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicInteger getAge() {returnage;

}public voidsetAge(Integer age) {this.age =age;

}publicString getAddress() {returnaddress;

}public voidsetAddress(String address) {this.address =address;

}

@OverridepublicString toString() {return "UserObj{" +

"uid=" + uid +

", name='" + name + '\'' +

", age=" + age +

", address='" + address + '\'' +

'}';

}

}

}

如上例子,可能抛出如下异常:

produce:UserObj{uid=2135, name='7QSy8X251t', age=44, address='2wwye8WEfR6dHJEQrIHk'}

An Exception: GC overhead limit exceeded occour..., cur uid:2136java.lang.OutOfMemoryError: GC overhead limit exceeded

consume user:UserObj{uid=1, name='nBf1Ck3T2G', age=20, address='7ubqHrfiHf5WEdPtbJak'}

at java.util.Arrays.copyOfRange(Arrays.java:3664)

at java.lang.String.(String.java:207)

at java.lang.StringBuilder.toString(StringBuilder.java:407)

at com.xxx.tester.OOMCatchTest.generateRandomStr(OOMCatchTest.java:98)

at com.xxx.tester.OOMCatchTest.productUserObj(OOMCatchTest.java:58)1541324629155: end producer.

at com.xxx.tester.OOMCatchTest$1.run(OOMCatchTest.java:26)

at java.lang.Thread.run(Thread.java:745)

Exception in thread"consumer-1"java.lang.OutOfMemoryError: GC overhead limit exceeded

at java.util.Arrays.copyOfRange(Arrays.java:3664)

at java.lang.String.(String.java:207)

at java.lang.StringBuilder.toString(StringBuilder.java:407)

at com.xxx.tester.OOMCatchTest$UserObj.toString(OOMCatchTest.java:145)

at java.lang.String.valueOf(String.java:2994)

at java.lang.StringBuilder.append(StringBuilder.java:131)

Exception in thread"consumer-1"java.lang.OutOfMemoryError: GC overhead limit exceeded

java.lang.OutOfMemoryError: GC overhead limit exceeded

An Exception: GC overhead limit exceeded occour..., cur uid:11743at java.util.Arrays.copyOf(Arrays.java:3332)

Exception in thread"producer-1"java.lang.OutOfMemoryError: GC overhead limit exceeded

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread"consumer-1"Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread"producer-1"produce:UserObj{uid=3751, name='dtXmpNGMs1', age=41, address='1Bujt5TzHv04cptNEyUb'}

An Exception: java.lang.OutOfMemoryError GC overhead limit exceeded occour..., cur uid:3752producer oom, wait:1producer oom, wait:2producer oom, wait:3

抛出OOM异常有几种情况:

1. java中直接throw 抛出 OOM;(后面详细列举)

2. 使用new int[MAX] 等基本类型方式时抛出 OOM,这种异常隐式抛出;

3. 当收到外部特殊信号时抛出,如:常用的威胁信号 kill -3 ;

而通常,前两个OOM都是可能被捕获的! 且抛出的OOM只会影响当前线程(和其他异常一样)。不过 OOM 一般会具有普遍性,即一个线程OOM时,通常其他线程也跑不掉!

下面来看几个JAVA中主动抛出 OOM 的样例吧:

// java.util.ArrayList.add(E e), 进行扩容的时候,就可能抛出oom, 也即代码异常,可以捕获

/*** Appends the specified element to the end of this list.

*

*@parame element to be appended to this list

*@returntrue (as specified by {@linkCollection#add})*/

public booleanadd(E e) {

ensureCapacityInternal(size+ 1); //Increments modCount!!

elementData[size++] =e;return true;

}private void ensureCapacityInternal(intminCapacity) {if (elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

minCapacity=Math.max(DEFAULT_CAPACITY, minCapacity);

}

ensureExplicitCapacity(minCapacity);

}private void ensureExplicitCapacity(intminCapacity) {

modCount++;//overflow-conscious code

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}/*** Increases the capacity to ensure that it can hold at least the

* number of elements specified by the minimum capacity argument.

*

*@paramminCapacity the desired minimum capacity*/

private void grow(intminCapacity) {//overflow-conscious code

int oldCapacity =elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)

newCapacity=minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity=hugeCapacity(minCapacity);//minCapacity is usually close to size, so this is a win:

elementData =Arrays.copyOf(elementData, newCapacity);

}private static int hugeCapacity(intminCapacity) {if (minCapacity < 0) //overflow

throw newOutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :

MAX_ARRAY_SIZE;

}//java.nio.ByteBuffer.allocateDirect(int capacity);//分配直接内存时,可能抛出oom

/*** Allocates a new direct byte buffer.

*

*

The new buffer's position will be zero, its limit will be its

* capacity, its mark will be undefined, and each of its elements will be

* initialized to zero. Whether or not it has a

* {@link#hasArray backing array} is unspecified.

*

*@paramcapacity

* The new buffer's capacity, in bytes

*

*@returnThe new byte buffer

*

*@throwsIllegalArgumentException

* If the capacity is a negative integer*/

public static ByteBuffer allocateDirect(intcapacity) {return newDirectByteBuffer(capacity);

}//java.nio.DirectByteBuffer

DirectByteBuffer(int cap) { //package-private

super(-1, 0, cap, cap);boolean pa =VM.isDirectMemoryPageAligned();int ps =Bits.pageSize();long size = Math.max(1L, (long)cap + (pa ? ps : 0));//此处先抛出oom

Bits.reserveMemory(size, cap);long base = 0;try{

base=unsafe.allocateMemory(size);

}catch(OutOfMemoryError x) {

Bits.unreserveMemory(size, cap);throwx;

}

unsafe.setMemory(base, size, (byte) 0);if (pa && (base % ps != 0)) {//Round up to page boundary

address = base + ps - (base & (ps - 1));

}else{

address=base;

}

cleaner= Cleaner.create(this, newDeallocator(base, size, cap));

att= null;

}//which a process may access. All sizes are specified in bytes.

static void reserveMemory(long size, intcap) {if (!memoryLimitSet &&VM.isBooted()) {

maxMemory=VM.maxDirectMemory();

memoryLimitSet= true;

}//optimist!

if(tryReserveMemory(size, cap)) {return;

}final JavaLangRefAccess jlra =SharedSecrets.getJavaLangRefAccess();//retry while helping enqueue pending Reference objects//which includes executing pending Cleaner(s) which includes//Cleaner(s) that free direct buffer memory

while(jlra.tryHandlePendingReference()) {if(tryReserveMemory(size, cap)) {return;

}

}//trigger VM's Reference processing

System.gc();//a retry loop with exponential back-off delays//(this gives VM some time to do it's job)

boolean interrupted = false;try{long sleepTime = 1;int sleeps = 0;while (true) {if(tryReserveMemory(size, cap)) {return;

}if (sleeps >=MAX_SLEEPS) {break;

}if (!jlra.tryHandlePendingReference()) {try{

Thread.sleep(sleepTime);

sleepTime<<= 1;

sleeps++;

}catch(InterruptedException e) {

interrupted= true;

}

}

}//no luck

throw new OutOfMemoryError("Direct buffer memory");

}finally{if(interrupted) {//don't swallow interrupts

Thread.currentThread().interrupt();

}

}

}//java.util.concurrentHashMap.toArray();//

public finalObject[] toArray() {long sz =map.mappingCount();if (sz >MAX_ARRAY_SIZE)//Required array size too large

throw newOutOfMemoryError(oomeMsg);int n = (int)sz;

Object[] r= newObject[n];int i = 0;for (E e : this) {if (i ==n) {if (n >=MAX_ARRAY_SIZE)throw newOutOfMemoryError(oomeMsg);if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)

n=MAX_ARRAY_SIZE;elsen+= (n >>> 1) + 1;

r=Arrays.copyOf(r, n);

}

r[i++] =e;

}return (i == n) ?r : Arrays.copyOf(r, i);

}

// java.nio.file.Files.readAllBytes(Path path)

public static byte[] readAllBytes(Path path) throwsIOException {try (SeekableByteChannel sbc =Files.newByteChannel(path);

InputStream in=Channels.newInputStream(sbc)) {long size =sbc.size();if (size > (long)MAX_BUFFER_SIZE)throw new OutOfMemoryError("Required array size too large");return read(in, (int)size);

}

}/*** Reads all the bytes from an input stream. Uses {@codeinitialSize} as a hint

* about how many bytes the stream will have.

*

*@paramsource

* the input stream to read from

*@paraminitialSize

* the initial size of the byte array to allocate

*

*@returna byte array containing the bytes read from the file

*

*@throwsIOException

* if an I/O error occurs reading from the stream

*@throwsOutOfMemoryError

* if an array of the required size cannot be allocated*/

private static byte[] read(InputStream source, int initialSize) throwsIOException {int capacity =initialSize;byte[] buf = new byte[capacity];int nread = 0;intn;for(;;) {//read to EOF which may read more or less than initialSize (eg: file//is truncated while we are reading)

while ((n = source.read(buf, nread, capacity - nread)) > 0)

nread+=n;//if last call to source.read() returned -1, we are done//otherwise, try to read one more byte; if that failed we're done too

if (n < 0 || (n = source.read()) < 0)break;//one more byte was read; need to allocate a larger buffer

if (capacity <= MAX_BUFFER_SIZE -capacity) {

capacity= Math.max(capacity << 1, BUFFER_SIZE);

}else{if (capacity ==MAX_BUFFER_SIZE)throw new OutOfMemoryError("Required array size too large");

capacity=MAX_BUFFER_SIZE;

}

buf=Arrays.copyOf(buf, capacity);

buf[nread++] = (byte)n;

}return (capacity == nread) ?buf : Arrays.copyOf(buf, nread);

}//java.io.BufferedInputStream.read()/skip()///java.io.BufferedInputStream.fill()

private void fill() throwsIOException {byte[] buffer =getBufIfOpen();if (markpos < 0)

pos= 0; /*no mark: throw away the buffer*/

else if (pos >= buffer.length) /*no room left in buffer*/

if (markpos > 0) { /*can throw away early part of the buffer*/

int sz = pos -markpos;

System.arraycopy(buffer, markpos, buffer,0, sz);

pos=sz;

markpos= 0;

}else if (buffer.length >=marklimit) {

markpos= -1; /*buffer got too big, invalidate mark*/pos= 0; /*drop buffer contents*/}else if (buffer.length >=MAX_BUFFER_SIZE) {throw new OutOfMemoryError("Required array size too large");

}else { /*grow buffer*/

int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?pos* 2: MAX_BUFFER_SIZE;if (nsz >marklimit)

nsz=marklimit;byte nbuf[] = new byte[nsz];

System.arraycopy(buffer,0, nbuf, 0, pos);if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {//Can't replace buf if there was an async close.//Note: This would need to be changed if fill()//is ever made accessible to multiple threads.//But for now, the only way CAS can fail is via close.//assert buf == null;

throw new IOException("Stream closed");

}

buffer=nbuf;

}

count=pos;int n = getInIfOpen().read(buffer, pos, buffer.length -pos);if (n > 0)

count= n +pos;

}

// java.lang.AbstractStringBuilder.expandCapacity(int minimumCapacity)

// java.lang.AbstractStringBuilder.ensureCapacityInternal(int minimumCapacity)

// java.lang.AbstractStringBuilder.append(String str)

/*** This implements the expansion semantics of ensureCapacity with no

* size check or synchronization.*/

void expandCapacity(intminimumCapacity) {int newCapacity = value.length * 2 + 2;if (newCapacity - minimumCapacity < 0)

newCapacity=minimumCapacity;if (newCapacity < 0) {if (minimumCapacity < 0) //overflow

throw newOutOfMemoryError();

newCapacity=Integer.MAX_VALUE;

}

value=Arrays.copyOf(value, newCapacity);

}

扩展,实际使用中捕获OOM的案例:

dubbo 捕获的 server 端的 OOM 异常示例如下:

2018-11-01 17:23:55.814 [DubboServerHandler-172.23.0.28:20880-thread-198] ERROR com.alibaba.dubbo.rpc.filter.ExceptionFilter - [DUBBO] Got unchecked and undeclared exception which called by 172.25.0.12. service: com.mobanker.xsxf.sxk.contract.basedata.RpcProtocolService, method: getUserProtocol, exception: java.lang.OutOfMemoryError: Java heap space, dubbo version: 3.0.0, current host: 172.23.0.28java.lang.OutOfMemoryError: Java heap space

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:423)

at com.alibaba.com.caucho.hessian.io.JavaDeserializer.instantiate(JavaDeserializer.java:271)

at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:155)

at com.alibaba.com.caucho.hessian.io.SerializerFactory.readObject(SerializerFactory.java:397)

at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObjectInstance(Hessian2Input.java:2070)

at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2005)

at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1990)

at com.alibaba.dubbo.common.serialize.support.hessian.Hessian2ObjectInput.readObject(Hessian2ObjectInput.java:88)

at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:94)

at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:117)

at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCodec.decodeBody(DubboCodec.java:98)

at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:134)

at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:95)

at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCountCodec.decode(DubboCountCodec.java:46)

at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.messageReceived(NettyCodecAdapter.java:134)

at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:80)

at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)

at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559)

at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)

at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)

at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)

at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:282)

at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:202)

at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)

at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

at java.lang.Thread.run(Thread.java:745)

捕获代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Overridepublic Result invoke(Invoker> invoker, Invocation invocation) throwsRpcException {try{

Result result=invoker.invoke(invocation);if (result.hasException() && GenericService.class !=invoker.getInterface()) {try{

Throwable exception=result.getException();//directly throw if it's checked exception

if (!(exception instanceof RuntimeException) && (exception instanceofException)) {returnresult;

}//directly throw if the exception appears in the signature

try{

Method method=invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());

Class>[] exceptionClassses =method.getExceptionTypes();for (Class>exceptionClass : exceptionClassses) {if(exception.getClass().equals(exceptionClass)) {returnresult;

}

}

}catch(NoSuchMethodException e) {returnresult;

}//for the exception not found in method's signature, print ERROR message in server's log.

logger.error("Got unchecked and undeclared exception which called by " +RpcContext.getContext().getRemoteHost()+ ". service: " + invoker.getInterface().getName() + ", method: " +invocation.getMethodName()+ ", exception: " + exception.getClass().getName() + ": " +exception.getMessage(), exception);//directly throw if exception class and interface class are in the same jar file.

String serviceFile =ReflectUtils.getCodeBase(invoker.getInterface());

String exceptionFile=ReflectUtils.getCodeBase(exception.getClass());if (serviceFile == null || exceptionFile == null ||serviceFile.equals(exceptionFile)) {returnresult;

}//directly throw if it's JDK exception

String className =exception.getClass().getName();if (className.startsWith("java.") || className.startsWith("javax.")) {returnresult;

}//directly throw if it's dubbo exception

if (exception instanceofRpcException) {returnresult;

}//otherwise, wrap with RuntimeException and throw back to the client

return new RpcResult(newRuntimeException(StringUtils.toString(exception)));

}catch(Throwable e) {

logger.warn("Fail to ExceptionFilter when called by " +RpcContext.getContext().getRemoteHost()+ ". service: " + invoker.getInterface().getName() + ", method: " +invocation.getMethodName()+ ", exception: " + e.getClass().getName() + ": " +e.getMessage(), e);returnresult;

}

}returnresult;

}catch(RuntimeException e) {

logger.error("Got unchecked and undeclared exception which called by " +RpcContext.getContext().getRemoteHost()+ ". service: " + invoker.getInterface().getName() + ", method: " +invocation.getMethodName()+ ", exception: " + e.getClass().getName() + ": " +e.getMessage(), e);throwe;

}

}

View Code

tomcat 中捕获OOM的异常示例如下:

28-Oct-2018 14:21:04.258严重 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run Unexpected death of background thread ContainerBackgroundProcessor[StandardEngine[Catalina]]

java.lang.OutOfMemoryError: Java heap space

Exceptionin thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" java.lang.OutOfMemoryError: Java heap space

捕获代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

//-------------------------------------- ContainerExecuteDelay Inner Class

/*** Private thread class to invoke the backgroundProcess method

* of this container and its children after a fixed delay.*/

protected class ContainerBackgroundProcessor implementsRunnable {

@Overridepublic voidrun() {

Throwable t= null;

String unexpectedDeathMessage=sm.getString("containerBase.backgroundProcess.unexpectedThreadDeath",

Thread.currentThread().getName());try{while (!threadDone) {try{

Thread.sleep(backgroundProcessorDelay* 1000L);

}catch(InterruptedException e) {//Ignore

}if (!threadDone) {

processChildren(ContainerBase.this);

}

}

}catch (RuntimeException|Error e) {

t=e;throwe;

}finally{if (!threadDone) {

log.error(unexpectedDeathMessage, t);

}

}

}protected voidprocessChildren(Container container) {

ClassLoader originalClassLoader= null;try{if (container instanceofContext) {

Loader loader=((Context) container).getLoader();//Loader will be null for FailedContext instances

if (loader == null) {return;

}//Ensure background processing for Contexts and Wrappers//is performed under the web app's class loader

originalClassLoader = ((Context) container).bind(false, null);

}

container.backgroundProcess();

Container[] children=container.findChildren();for (int i = 0; i < children.length; i++) {if (children[i].getBackgroundProcessorDelay() <= 0) {

processChildren(children[i]);

}

}

}catch(Throwable t) {

ExceptionUtils.handleThrowable(t);

log.error("Exception invoking periodic operation: ", t);

}finally{if (container instanceofContext) {

((Context) container).unbind(false, originalClassLoader);

}

}

}

}

View Code

总结:

1. oom异常一般是java程序在做内存分配时,发现没有足够的剩余空间可用而抛出的异常;

2. 此时的分配空间可能是出于代码的new操作(用户主动),可能是出于内存的复制操作(语言自动),也可能是出于内存数据的重振操作(语言自动),可能是出jvm检测到外部信号(jvm自动);

3. oom只是被建议为不要捕获的异常,因为通常你对这种情况是无能为力的!但你如果实在要捕获,why not ?

4. oom一般只会影响当前线程,而jvm中只要存在一个非daemon线程在运行,jvm就不会退出;

5. 如果是线程池运行环境,一般需要一个统一管理oom的程序,否则不能及时统一处理oom;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值