java 交叉引用 会java内存溢出怎么解决吗

4799人阅读
java基础(29)
虽然jvm可以通过GC自动回收无用的内存,但是代码不好的话仍然存在内存溢出的风险。
最近在网上搜集了一些资料,现整理如下:
一、为什么要了解内存泄露和内存溢出?
1、内存泄露一般是代码设计存在缺陷导致的,通过了解内存泄露的场景,可以避免不必要的内存溢出和提高自己的代码编写水平;
2、通过了解内存溢出的几种常见情况,可以在出现内存溢出的时候快速的定位问题的位置,缩短解决故障的时间。
&二、基本概念
理解这两个概念非常重要。
内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存。即被分配的对象可达但已无用。
内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。
从定义上可以看出内存泄露是内存溢出的一种诱因,不是唯一因素。
三、内存泄露的几种场景:
1、长生命周期的对象持有短生命周期对象的引用
& & & & & & 这是内存泄露最常见的场景,也是代码设计中经常出现的问题。
& & & & & & 例如:在全局静态map中缓存局部变量,且没有清空操作,随着时间的推移,这个map会越来越大,造成内存泄露。
2、修改hashset中对象的参数值,且参数是计算哈希值的字段
& & & & & & &当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段,否则对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中删除当前对象,造成内存泄露。
3、机器的连接数和关闭时间设置
& & & & & & 长时间开启非常耗费资源的连接,也会造成内存泄露。
&四、内存溢出的几种情况:
1、堆内存溢出(outOfMemoryError:java heap space)
& & & &在jvm规范中,堆中的内存是用来生成对象实例和数组的。
& & & &如果细分,堆内存还可以分为年轻代和年老代,年轻代包括一个eden区和两个survivor区。
& & & &当生成新对象时,内存的申请过程如下:
& & & & & a、jvm先尝试在eden区分配新建对象所需的内存;
& & & & & b、如果内存大小足够,申请结束,否则下一步;
& & & & & c、jvm启动youngGC,试图将eden区中不活跃的对象释放掉,释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
& & & & & d、Survivor区被用来作为Eden及old的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区;
& & & & & e、&当OLD区空间不够时,JVM会在OLD区进行full GC;
& & & & & f、full GC后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”:
& & & & & & & & & & & & & & & & & &outOfMemoryError:java heap space
代码举例:
* 堆内存溢出
* jvm参数:-Xms5m -Xmx5m -Xmn2m -XX:NewSize=1m
public class MemoryLeak {
private String[] s = new String[1000];
public static void main(String[] args) throws InterruptedException {
Map&String,Object& m =new HashMap&String,Object&();
int j=10000;
while(true){
for(;i&j;i++){
MemoryLeak memoryLeak = new MemoryLeak();
m.put(String.valueOf(i), memoryLeak);
&& & & & &&
2、方法区内存溢出(outOfMemoryError:permgem space)
& & & &在jvm规范中,方法区主要存放的是类信息、常量、静态变量等。
& & & &所以如果程序加载的类过多,或者使用反射、gclib等这种动态代理生成类的技术,就可能导致该区发生内存溢出,一般该区发生内存溢出时的错误信息为:
& & & & & & &outOfMemoryError:permgem space
代码举例:
jvm参数:-XX:PermSize=2m -XX:MaxPermSize=2m
将方法区的大小设置很低即可,在启动加载类库时就会出现内存不足的情况
3、线程栈溢出(java.lang.StackOverflowError)
& & & &线程栈时线程独有的一块内存结构,所以线程栈发生问题必定是某个线程运行时产生的错误。
& & & &一般线程栈溢出是由于递归太深或方法调用层级过多导致的。
& & & &发生栈溢出的错误信息为:
& & & & & & & java.lang.StackOverflowError
代码举例:
* 线程操作栈溢出
* 参数:-Xms5m -Xmx5m -Xmn2m -XX:NewSize=1m -Xss64k
public class StackOverflowTest {
public static void main(String[] args) {
private static void digui(int i){
System.out.println(i++);
String[] s = new String[50];
五、为了避免内存泄露,在编写代码的过程中可以参考下面的建议:
1、尽早释放无用对象的引用
2、使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域
3、尽量少用静态变量,因为静态变量存放在永久代(方法区),永久代基本不参与垃圾回收
4、避免在循环中创建对象
5、开启大型文件或从数据库一次拿了太多的数据很容易造成内存溢出,所以在这些地方要大概计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。&
/question/.html & &
/developerworks/cn/java/l-JavaMemoryLeak/ &Java的内存泄漏
http://jelly-/blog/1120406 JVM内存分析及导致内存溢出
/view/efb0717fd5ddda.html java内存泄露和内存溢出
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1585335次
积分:16697
积分:16697
排名:第371名
原创:206篇
转载:27篇
译文:55篇
评论:1747条
文章:10篇
阅读:46512
文章:21篇
阅读:141179
文章:44篇
阅读:610132
(4)(2)(2)(1)(8)(1)(2)(1)(1)(8)(2)(1)(1)(1)(3)(3)(2)(1)(3)(1)(1)(13)(3)(3)(5)(8)(2)(7)(5)(8)(3)(6)(3)(1)(4)(1)(5)(6)(4)(2)(2)(5)(2)(6)(12)(8)(1)(4)(2)(4)(1)(5)(3)(5)(2)(6)(1)(6)(9)(7)(16)(10)(4)(2)(3)(24)(转)java用Socket实现的远程桌面浏览&内存溢出问题
用socket做长连接时,出现了内存溢出的错误。搞了4天的时间总算是搞定了。
现总结下:
1.socket一般分为短连接和长连接。
长连接是一旦一个客户端登陆上服务器,其与服务器之间的连接就不关闭,不管他们之间进行了多少次交易,直到客户端退出登陆或网络出现故障。这种技术在联机交易系统实现有利于提高效率。&&
短连接是客户端每发一个请求就与服务器建立一个连接,交易完成后关闭连接,这种技术实现较长连接简单。
长:connect连上后不断开,&&
进行N次收发操作.&&
短:每次都connect,&&
完成任务后立即断开.&&
下次重连.&&
一般都是accept后启动一个线程去处理,该线程中的处理大致如下&&
& 短连接:&&
& run(){&&
read&&&&&&&&&&
//读取请求包&&
process&&&&
write&&&&&&&&
//应答处理结果&&
& 长连接:&&
& run(){&&
while(NotEnd){&&
短连接进行一次连接做完业务逻辑处理后就关闭连接,关闭了socket连接也就释放了socket所占用的资源,所以不会出现内存溢出的问题。
长连接一般是连接上服务器后,会做一个循环的业务逻辑处理。如果这个时候我们不得不在循环里创建对象发送到服务器端做处理然后服务器端(反之亦然),那么就有可能出现内存溢出的问题。
例如下面实现的远程桌面的程序:
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();
&&&&&&&&&&&&&&&&}&
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&image&=&robot.createScreenCapture(screenRect);
&&&&&&&&&&&&&&&&ByteArrayOutputStream&byteOutStream&=&new&ByteArrayOutputStream();
&&&&&&&&&&&&&&&&JPEGImageEncoder&encoder&=
&&&&&&&&&&&&&&&&&&&&JPEGCodec.createJPEGEncoder(byteOutStream);
&&&&&&&&&&&&&&&&JPEGEncodeParam&param&=&encoder.getDefaultJPEGEncodeParam(image);
&&&&&&&&&&&&&&&&param.setQuality(0.5f,&false);
&&&&&&&&&&&&&&&&encoder.setJPEGEncodeParam(param);
&&&&&&&&&&&&&&&&encoder.encode(image);
&&&&&&&&&&&&&&&&ScreenImageInfo&imageInfo&=
&&&&&&&&&&&&&&&&&&&&new&ScreenImageInfo(byteOutStream.toByteArray());
&&&&&&&&&&&&&&&&out.writeObject(imageInfo);
&&&&&&&&&&}
&&&&&&&&}&
&上面的客户端循环的创建对象,服务器端循环的读出。由于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);//客户端的超时时间
&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&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&image&=&robot.createScreenCapture(screenRect);
&&&&&&&&&&ByteArrayOutputStream&byteOutStream&=&new&ByteArrayOutputStream();
&&&&&&&&&&JPEGImageEncoder&encoder&=
&&&&&&&&&&&&&&JPEGCodec.createJPEGEncoder(byteOutStream);
&&&&&&&&&&JPEGEncodeParam&param&=&encoder.getDefaultJPEGEncodeParam(image);
&&&&&&&&&&param.setQuality(0.5f,&false);
&&&&&&&&&&encoder.setJPEGEncodeParam(param);
&&&&&&&&&&encoder.encode(image);
&&&&&&&&&&ScreenImageInfo&imageInfo&=
&&&&&&&&&&&&&&new&ScreenImageInfo(byteOutStream.toByteArray());
&&&&&&&&&&out.writeObject(imageInfo);
&&&&&&&&}&
&修改后的服务器端和客户端socket,虽然也没有一直得到释放,但是ObjectInputStream&
ObjectInputStream(clientSkt.getInputStream());和ObjectOutputStream
ObjectOutputStream(clientSkt.getOutputStream());在循环中每次都会生成新的
ObjectInputStream& 和ObjectOutputStream
对象,并且该对象的引用也不会被socket所持有。所以java的垃圾回收器可以回收这些对象,不会出现内存溢出的问题。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。JAVA内存溢出解析(携程面试)
核心提示:原因有很多种,比如: 1.数据量过于庞大;死循环
;静态变量和静态方法过多;递归;无法确定是否被引用的对象;比如代码中递归的次数过于多,内存中不停的进栈,那,没有出栈的条件,就会栈溢出
2.虚拟机不回收内存(内存泄漏); 说白了就是程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了。
内存溢出的问题要看业务和系
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&java 大数组内存溢出
[问题点数:80分,结帖人march_on]
java 大数组内存溢出
[问题点数:80分,结帖人march_on]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2013年5月 挨踢职涯大版内专家分月排行榜第二
2013年9月 Java大版内专家分月排行榜第三
2013年10月 Java大版内专家分月排行榜第二2013年3月 Java大版内专家分月排行榜第二2013年2月 Java大版内专家分月排行榜第二
2013年7月 Java大版内专家分月排行榜第三2013年5月 Java大版内专家分月排行榜第三2013年4月 Java大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。

我要回帖

更多关于 java内存溢出怎么解决 的文章

 

随机推荐