ejb与java序列化(1) 发现并分析问题

这是加入新公司后接手的第一个项目,使用weblogic9.2 + ejb2.0,压力测试时发现速度非常慢,响应时间很不理想,检查日志发现,某些ejb相互调用时方法调用的时间非常长,高达300-500毫秒。非常夸张,因为两个日志之间只是间隔了一个ejb调用。通过thread dump分析后发现有相当多的线程在wait,检查线程调用绽发现是在将参数进行序列化时,线程试图加锁但是锁被占用,因此处于等待状态。考虑到thread dump的这一瞬间,有多达30-50个线程都在同时试图在同一个锁上加锁,很明显这里的锁竞争非常严重。

因此强烈怀疑是java的序列化机制导致的问题,由于weblogic/ejb之类的太复杂不方便测试,因此单独写了一个类来模拟这种场景:
1.有大量线程在运行,期间都有序列化的操作
2.被序列化的对象比较大,有大量子对象(子对象的子对象...)

运行测试代码,问题重现,测试用开了50个线程,thread dump并分析thread dump信息,发现49个线程处于waiting 状态,只有一个线程在干活!因此抛开weblogic/ejb单独分析java的序列化机制,首先看thread dump的线程信息:

占有锁的线程:

"testthread21" prio=6 tid=0x0ad2d3b8 nid=0x224 runnable [0x0b48f000..0x0b48fce4]
at java.io.ObjectStreamClass.processQueue(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at test.Test.test(Test.java:68)
at test.Test.run(Test.java:53)
at java.lang.Thread.run(Unknown Source)

等待加锁的线程之一: "testthread49" prio=6 tid=0x0ad9a508 nid=0xa9c waiting for monitor entry [0x0bb8f000..0x0bb8fbe4]
at java.lang.ref.ReferenceQueue.poll(Unknown Source)
- waiting to lock <0x02fb1d40> (a java.lang.ref.ReferenceQueue$Lock)
at java.io.ObjectStreamClass.processQueue(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at test.Test.test(Test.java:68)
at test.Test.run(Test.java:53)
at java.lang.Thread.run(Unknown Source)

可以发现问题发生在类java.io.ObjectStreamClass中的方法processQueue()方法中: static void processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends
WeakReference<Class<?>>, ?> map)
{
Reference<? extends Class<?>> ref;
while((ref = queue.poll()) != null) {
map.remove(ref);
}
}

这里的queue.poll()有加锁,继续跟进poll()的代码: public Reference<? extends T> poll() {
if(queueEmpty) return null;
synchronized (lock) {
return reallyPoll();
}
}

时间: 2024-10-21 20:26:45

ejb与java序列化(1) 发现并分析问题的相关文章

ejb与java序列化(3) 开启enable-call-by-reference

问题终于找到,简单的说是因为java 序列化的效率低下,而ejb调用之间又大量使用序列化,因此造成极大的性能消耗,而且也影响到响应时间.仔细分析了一下项目情况,呵呵,情况非常严重,系统架构是按照三层来设计的,每个层都是ejb,调下一层都是通过远程接口,而且层之间可能还多个ejb的调用. (说句题外话,这种设计个人感觉非常,恩,不理解,性能杀手,而且ejb配置极其复杂,当然或者ejb本来就是如此,ebj和weblogic对我来说是很陌生很高深的东西,目前还没有深入掌握.) 很自然的会想到ejb2.

ejb与java序列化(2) 测试代码

接上篇,有兴趣的朋友可以直接拿我的测试代码自行测试,请自行修改诸如线程数,执行时间,序列化的数据量大小等参数.如果想尝试做thread dump,可以打开相关的两个注释,会更方便一些,代码中都有相应的注释可供参考. 测试代码如下: package test; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Seri

Java 序列化的高级认识

引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 进行对象的读写.然而在有些情况下,光知道这些还远远不够,文章列举了笔者遇到的一些真实情境,它们与 Java 序列化相关,通过分析情境出现的原因,使读者轻松牢记 Java 序列化中的一些高级认识. ----------

PHP序列化/对象注入漏洞分析_php技巧

本文是关于PHP序列化/对象注入漏洞分析的短篇,里面讲述了如何获取主机的远程shell. 如果你想自行测试这个漏洞,你可以通过 XVWA 和 Kevgir 进行操作. 漏洞利用的第一步,我们开始测试目标应用是否存在PHP序列化.为了辅助测试,我们使用了Burpsuite的SuperSerial插件,下载地址在 这里 .它会被动检测PHP和Java序列化的存在. 分析 我们检测到了应用里使用了PHP序列化,所以我们可以开始确认应用代码里是否含有远程代码执行漏洞.需要注意的是,序列化对象是从参数"r

java序列化与反序列化操作实例分析_java

本文实例分析了java序列化与反序列化操作.分享给大家供大家参考,具体如下: 概述: Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程. 示例代码: import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.i

java序列化的控制

正如大家看到的那样,默认的序列化机制并不难操纵.然而,假若有特殊要求又该怎么办呢?我们可能有特殊的安全问题,不希望对象的某一部分序列化:或者某一个子对象完全不必序列化,因为对象恢复以后,那一部分需要重新创建. 此时,通过实现Externalizable接口,用它代替Serializable接口,便可控制序列化的具体过程.这个Externalizable接口扩展了Serializable,并增添了两个方法:writeExternal()和readExternal().在序列化和重新装配的过程中,会

Java序列化——transient关键字和Externalizable接口

    提到Java序列化,相信大家都不陌生.我们在序列化的时候,需要将被序列化的类实现Serializable接口,这样的类在序列化时,会默认将所有的字段都序列化.那么当我们在序列化Java对象时,如果不希望对象中某些字段被序列化(如密码字段),怎么实现呢?看一个例子: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.io.Serializable; import java.util

java 序列化

1.java序列化的作用 序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得.  序列化分为两大部分:序列化和反序列化.序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输.反序列化就是打开字节流并重构对象.对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据.恢复数据要求有恢复数据的对象实例  序列化的什么特点:  如果某个类能够被序列化,其子类也可以被序列化.声明为static和transient类型的成员数据不能被序列化.因为sta

Java序列化与反序列化

1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频.视频等都是通过二进制序列进行传输的,那么如果我们需要将Java对象进行传输的时候,是不是也应该先将对象进行序列化?答案是肯定的,我们需要先将Java对象进行序列化,然后通过网络,IO进行传输,当到达目的地之后,再进行反序列化获取到我们想要的对象,最后完成通信. 2.如何实现序列化 2.1.使用到JD