此第三方脚本不断导致堆内存异常:
byte[] forwardMessage(byte[] content) {
s = new Socket("172.17.0.30", 10001);
s.withStreams {InputStream input, OutputStream output ->
output.write content
return readRtsData(input)
}
}
byte[] readRtsData(input) {
def vplEndByte = 0xff
def inStream = new BufferedInputStream(input)
def bytes = []
while (bytes.isEmpty() || bytes.last() != vplEndByte) {
bytes.add(inStream.read())
}
bytes
}
脚本的一部分在收到消息后通过TCP / IP接收消息,导致以下异常:
线程“Thread-2”中的异常 org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.OutOfMemoryError:Java堆 空间 在org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:92) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234) 在org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:880) 在groovy.lang.Closure.call(Closure.java:279) 在groovy.lang.Closure.call(Closure.java:292) 在org.codehaus.groovy.runtime.DefaultGroovyMethods $ 6.run(DefaultGroovyMethods.java:11563) 在java.lang.Thread.run(Thread.java:636) 引起:java.lang.OutOfMemoryError: Java堆空间 at java.util.Arrays.copyOf(Arrays.java:2746) at java.util.ArrayList.ensureCapacity(ArrayList.java:187) at java.util.ArrayList.add(ArrayList.java:378) at sun.reflect.GeneratedMethodAccessor9.invoke(未知 资源) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:616) at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite $ PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229) 在org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52) 在org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) 在RTSGatewayServer.readRtsData(RTSGatewayServer.groovy:46) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native 方法) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:616) 在org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234) 在org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:361) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:880) 在org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66) 在org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:151) 在RTSGatewayServer $ _forwardMessage_closure2.doCall(RTSGatewayServer.groovy:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native 方法) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:616) 在org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234) 在org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:880) 在groovy.lang.Closure.call(Closure.java:279) at org.codehaus.groovy.runtime.DefaultGroovyMethods.withStreams(DefaultGroovyMethods.java:11462) 在org.codehaus.groovy.runtime.dgm $ 658.invoke(未知 源)
我猜测使用bytes.add(...)
会有更好的内存效率吗?
如果有人能够将结果与.NET中发生的事情进行比较,那将会更好,因为我是.NET开发人员。
答案 0 :(得分:3)
因此脚本会一直读取和存储字节,直到看到0xff。
这似乎是一个有缺陷的设计。无论你如何调整JVM,你最终可能会耗尽memry。如果远程服务选择在0xff之前发送peta字节的详细信息,那么你将耗尽内存。我的看法是你应该总是假设其他参与者可能被打破或反社会。
因此,我会对我准备接受的数据设置一些上限。然后,如果可能的话,处理你已收到的块并返回并获取下一个块,或者如果不能以块的形式处理,则礼貌地发出错误消息并停止。
底线:清理您的输入。允许外部过程耗尽你的记忆是一件坏事。当他们说“不可能发生”时,不要相信他们。
答案 1 :(得分:1)
用 - Xmx调整jvm ......?
答案 2 :(得分:1)
它实际上是来自Socket的数据导致OutofMemory吗?
如果您使用的是Java 6,请使用jconsole连接到服务器并查看堆。
答案 3 :(得分:0)
如果您阅读合同,
InputStream.read():int
当流结束时,返回-1。
因此,如果流不具有0xff字符(例如,如果流在接收到0xff之前结束),则此代码将永久地将接收到的最后一个字节(例如-1)附加到该数组! / p>
明确修复:
while (bytes.isEmpty() || bytes.last() != vplEndByte || bytes.last != -1) {
// ---其他问题
虽然您应该在此代码上设置上限以避免OOM,但您遇到的具体问题是
def bytes = [] //[] is shorthand for "new ArrayList()"
这将创建一个ArrayList,一个数组支持的数据结构,它通过分配一个数组开始,并在每次达到前一个容量时将其大小增加一倍。我相信默认大小只有10个元素。
因此,你在这里隐式地创建了大量的数组,这就是堆栈跟踪的混乱所抱怨的。在具有几K到M的适度大小消息的高性能应用程序中,您可能比GC可以更快地分配新阵列。
您应该考虑使用合理的初始大小创建该arraylist,以减少隐式对象实例化并引入合理的最大边界。您也可以将该集合切换到链接列表,但可能会降低性能。