由于java.lang.OutOfMemoryError,RMI线程终止:Java堆空间

时间:2009-01-28 13:43:02

标签: multithreading rmi

我正在开发基于comp的应用程序。 在此应用程序中,有n个容器通过它们彼此提供的RMI服务相互通信。 在证书点,连接到我的容器的一个rmi线程由于内存不足错误而丢失连接,但连接到我的容器的所有其他RMI线程都正常工作。

错误的堆栈目标在这里:

Exception dispatching call to [655d565c:11f1d5dbae2:-7ffb, -3259564578052694518] in thread "RMI TCP Connection(21)-132.186.96.179" at Wed Jan 28 18:50:37 GMT+05:30 2009: 
java.lang.OutOfMemoryError: Java heap space
    at java.lang.reflect.Array.newArray(Native Method)
    at java.lang.reflect.Array.newInstance(Unknown Source)
    at java.io.ObjectInputStream.readArray(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

要查看此异常,我必须激活特定于RMI的日志记录。出现此问题是因为此终止线程的每个RMI调用都会将一些数据添加到我的容器堆中。 在某些时候它的大小超出。

我的问题是,如果我的容器的堆大小内存不足,为什么其他线程正在工作? 如果您有任何想法,请告诉我。

2 个答案:

答案 0 :(得分:3)

失败的电话是

java.lang.reflect.Array.newArray(Native Method)

这意味着失败的RMI线程正在尝试分配数组。不幸的是,它并没有告诉我们它试图分配的阵列有多大。它试图分配一个巨大的数组,并且失败了,那么这不会伤害任何其他线程。失败的请求是否有任何不同之处,它必须分配更多的内存而不是正在进行的其他请求?

详细说明......让我们说由于某种原因,这一个请求试图分配一个500兆的数组(并且堆上没有足够的内存)。好吧, 分配请求将失败。但只要堆仍有足够的内存用于正常的分配请求,其他线程就不会有创建新对象的问题。

答案 1 :(得分:3)

简单回答:因为其他操作没有失败操作的内存要求。

更长的答案从查看堆栈跟踪开始:

java.lang.OutOfMemoryError: Java heap space at java.lang.reflect.Array.newArray(Native Method) at
java.lang.reflect.Array.newInstance(Unknown Source) at java.io.ObjectInputStream.readArray(Unknown Source) at
java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.defaultReadFields(Unknown
...
sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) at  

因此,失败的线程正在尝试创建一个新数组,以便处理传入的请求。如果该数组特别大,那么请求处理程序可能无法分配它,而使用较少数据量的其他请求将处理没有问题。

所以,第一个问题是:该阵列有多大?您应该在客户端进行一些日志记录以确定这一点。如果特定客户端尝试发送异常大的数组,则可能需要减小其大小。

第二个问题:你有没有给服务器JVM足够的内存来处理预期的负载? Jave是少数几个仍需要你告诉它程序需要多少内存的环境之一,默认值非常小(我相信64M)。查看-ms和-mx参数以了解如何增加它。