用socket作长链接时,出现了内存溢出的错误。搞了4天的时间总算是搞定了。java
现总结下:服务器
1.socket通常分为短链接和长链接。网络
长链接是一旦一个客户端登录上服务器,其与服务器之间的链接就不关闭,无论他们之间进行了多少次交易,直到客户端退出登录或网络出现故障。这种技术在联机交易系统实现有利于提升效率。
短链接是客户端每发一个请求就与服务器创建一个链接,交易完成后关闭链接,这种技术实现较长链接简单。
长:connect连上后不断开, 进行N次收发操做.
短:每次都connect, 完成任务后当即断开. 下次重连.
通常都是accept后启动一个线程去处理,该线程中的处理大体以下
短链接:
run(){
read //读取请求包
process //处理
write //应答处理结果
}
长链接:
run(){
while(NotEnd){
read
process
write
}
}socket
2. 短链接进行一次链接作完业务逻辑处理后就关闭链接,关闭了socket链接也就释放了socket所占用的资源,因此不会出现内存溢出的问题。ide
长链接通常是链接上服务器后,会作一个循环的业务逻辑处理。若是这个时候咱们不得不在循环里建立对象发送到服务器端作处理而后服务器端(反之亦然),那么就有可能出现内存溢出的问题。spa
例以下面实现的远程桌面的程序:线程
服务器端code
- com.hjdf.calis.cvrs.util.CvrsSystem.println(serverPort + " 等待链接中......");
- serverSkt.setSoTimeout(10*60*1000);//服务器端的超时时间
- clientSkt = serverSkt.accept();
- com.hjdf.calis.cvrs.util.CvrsSystem.println(serverPort+"与" +
- clientSkt.getInetAddress() + " 创建链接");
- clientSkt.setSoTimeout(60*1000);//客户端的超时时间
- ObjectOutputStream out = new ObjectOutputStream(clientSkt.getOutputStream());
- ObjectInputStream in= new ObjectInputStream(clientSkt.getInputStream());
- ObjectOutputStream pipeout = new ObjectOutputStream(outputstream);
- ObjectInputStream pipein = new ObjectInputStream(inputstream);
- String pipstr="GET";
- if(iswrite){
- pipstr = (String) pipein.readObject();
- if (pipstr != null) {
- out.writeObject(pipstr);
- }
- iswrite =false;
- }else{
- out.writeObject(pipstr);
- out.flush();
- }
- ScreenImageInfo screenInfo= (ScreenImageInfo)in.readObject();
- while(screenInfo!=null){
- pipeout.writeObject(screenInfo);
- if(iswrite){
- pipstr = (String) pipein.readObject();
- if (pipstr != null) {
- out.writeObject(pipstr);
- }
- iswrite =false;
- }else{
- out.writeObject(pipstr);
- out.flush();
- }
- screenInfo= (ScreenImageInfo)in.readObject();
- }
客户端server
- ObjectInputStream in= new ObjectInputStream(clientSkt.getInputStream());
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Dimension screenSize = toolkit.getScreenSize();
- Rectangle screenRect = new Rectangle(screenSize);
- Robot robot = new Robot();
- ObjectOutputStream out = new ObjectOutputStream(clientSkt.getOutputStream());
- while ( (clientCom = (String) in.readObject()) != null) {
- if (clientCom.equals("GET")) {
- BufferedImage p_w_picpath = robot.createScreenCapture(screenRect);
- ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
- JPEGImageEncoder encoder =
- JPEGCodec.createJPEGEncoder(byteOutStream);
- JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(p_w_picpath);
- param.setQuality(0.5f, false);
- encoder.setJPEGEncodeParam(param);
- encoder.encode(p_w_picpath);
- ScreenImageInfo p_w_picpathInfo =
- new ScreenImageInfo(byteOutStream.toByteArray());
- out.writeObject(p_w_picpathInfo);
- }
- }
上面的客户端循环的建立对象,服务器端循环的读出。因为socket流一直没有获得释放,socket流中会一直持有新建立的ScreenImageInfo对象的引用,这样java的垃圾回收器不会回收循环建立的对象,致使内存溢出。对象
修改服务器端和客户端,解决内存溢出:
服务器
- com.hjdf.calis.cvrs.util.CvrsSystem.println(serverPort + " 等待链接中......");
- serverSkt.setSoTimeout(10*60*1000);//服务器端的超时时间
- clientSkt = serverSkt.accept();
- com.hjdf.calis.cvrs.util.CvrsSystem.println(serverPort+"与" +
- clientSkt.getInetAddress() + " 创建链接");
- clientSkt.setSoTimeout(60*1000);//客户端的超时时间
- /**
- * 把流在循环里建立,每次都生成新的对象,垃圾回收器能够回收之前的ScreenImageInfo对象。
- * 若是流在循环外建立,流中会持有循环建立的ScreenImageInfo的对象的引用,
- * ScreenImageInfo的对象不能被回收,致使内存溢出的错误。
- **/
- while(true){
- ObjectInputStream in= new ObjectInputStream(clientSkt.getInputStream());
- ObjectOutputStream pipeout = new ObjectOutputStream(outputstream);
- ScreenImageInfo screenInfo= (ScreenImageInfo)in.readObject();
- if(screenInfo!=null){
- pipeout.writeObject(screenInfo);
- }
- }
客户端
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Dimension screenSize = toolkit.getScreenSize();
- Rectangle screenRect = new Rectangle(screenSize);
- Robot robot = new Robot();
- while(true){
- ObjectOutputStream out = new ObjectOutputStream(clientSkt.getOutputStream());
- BufferedImage p_w_picpath = robot.createScreenCapture(screenRect);
- ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
- JPEGImageEncoder encoder =
- JPEGCodec.createJPEGEncoder(byteOutStream);
- JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(p_w_picpath);
- param.setQuality(0.5f, false);
- encoder.setJPEGEncodeParam(param);
- encoder.encode(p_w_picpath);
- ScreenImageInfo p_w_picpathInfo =
- new ScreenImageInfo(byteOutStream.toByteArray());
- out.writeObject(p_w_picpathInfo);
- }
修改后的服务器端和客户端socket,虽然也没有一直获得释放,可是ObjectInputStream in= new ObjectInputStream(clientSkt.getInputStream());和ObjectOutputStream out = new ObjectOutputStream(clientSkt.getOutputStream());在循环中每次都会生成新的ObjectInputStream 和ObjectOutputStream 对象,而且该对象的引用也不会被socket所持有。因此java的垃圾回收器能够回收这些对象,不会出现内存溢出的问题。