紫风乱写

除了他眼前的屏幕,这个人什么也没看见。
被周围的电脑簇拥着,他只知道他所创造的现实,但又意识到那是虚幻。
他已经超越了技术。也超越了机器。
posts - 62, comments - 93, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

病中吟之内存溢出

Posted on 2015-06-08 19:13 Justfly Shi 阅读(3967) 评论(4)  编辑  收藏 所属分类: 随便写写

感冒了,在家里休息,打开电脑随便看看,想起前两天有人问的一个事情:“内存溢出怎么分析和处理?”方案有很多了,基本上的思路就是获取系统状态,内存变化方向,内存对象等之类的,profile,debug,jmx,dump等等。

我更想说的是,为什么会内存溢出呢?

在我看来,干活有两种方式:

  • 没想清楚了,贸贸然开干,然后各处救火各种解决问题
  • 想清楚了再开干,无惊无险,安然做完

一般来说,我都是后者,所以真的很少碰到各种莫名其妙的问题,比如自己实现排序算法、在内存中处理有100000个值的列表、不用第三个变量来交换两个变量的值等等。

怎么避免内存溢出

吐槽完毕,来说说对于内存溢出这种事情是要怎么避免,我所谓的“想清楚了再开干”到底是怎么想清楚的。

首先内存溢出的本质是什么?“内存使用超出了预期”。 
那么要怎么避免呢?“预期内存怎么使用,将其控制在内存使用范围呢”。

如何预期内存的使用

Java程序中,内存是被怎么占用的?被数据和对象占用的,数据和对象怎么来的?

  • 应用的输入和输出
  • 第三方系统的输入和输出
  • 应用本身产生的数据

如何控制内存的使用

应用输入和输出怎么控制

  • 控制允许输入的线程数,比如允许同时多少个线程提供服务
  • 控制输入的请求对象的大小和内容,比如输入时的所允许的缓冲区大小
  • 输出的线程数是和输入的线程对应的,如果是主动输出的,那么就控制一下
  • 输出的服务对象的大小和内容,比如你是文件服务器,那么设置一个输出缓存,每10K就Flush一下。

第三方系统的输入和输出怎么控制

思路和应用输入和输出怎么控制所说的是一样的,控制线程数,使用缓存控制。

应用本身产生的数据怎么控制

思路也是一样的,线程数,缓存,再加上生存时间,对象池等等。

还有?

使用上述技巧和思路你就能控制好你应用中的内存了,但是所有的设计都是在风险和满足需求之间的平衡,如果再退一步,那么你需要考虑一下Java虚拟机中内存各个区的使用了。你需要区分好哪些是常驻对象,哪些是临时对象,新生代,旧生代,怎么安排你的虚拟机中各个内存区的大小。希望你不需要用到,如果需要的话,可以看看《深入理解Java虚拟机》这本书。

来个例子

有这么一个应用,它获取客户端的请求,验证请求的合法性,然后对于合法的请求,从第三方系统获取文件内容,并把文件内容写回给客户端。 
下面是一大片的空白,再滚动下去之前看我的设计之前,读者可以就这个需求想想你会怎么处理。 







































|

应用本身的的输入和输出的控制

  • 同时服务数设置为可配置的属性,来控制并行的服务数
  • 请求只允许Get请求,请求内容只有Header和URL,设置一个输入Buffer
  • 输出,设置输出缓存区的大小,可配置的,默认情况下,每20K Flush一下。

第三方系统的输入和输出

第三方系统有两个,一个是合法性验证的,一个是文件内容的。 
合法性验证的请求和输出的内容都比较小。但是考虑到其服务器的性能,把合法性验证的交互过程放到一个线程池中控制。这样能避免合法性验证服务不过来的情况。

文件内容第三方系统的输入和输出的控制

  • 和合法性验证一样,文件内容第三方系统的输入和输出能力有限,将其访问用线程池控制起来。
  • 文件内容第三方系统的请求访问对象较小,不予控制
  • 整个系统的最重点来了!文件内容第三方系统的返回文件大小不可控制。所以使用缓存机制,每次读入20K(可配置),然后写给系统的客户端,然后再读20K,然后再写,让文件内容从这个系统中像水一样流过去。流不动了(第三方系统连接或者客户端连接失败)就让本次服务失败。这个流过去就是重点了,不管这个文件多大,每次请求只占用20K。

应用本身产生的数据

最原始的需求中还有一个把文件内容缓存在本地,然后可以多次写给客户端的这么一个想法,减少网络等待。这个想法被我否决了,原因如下:

  • 首先可以通过HTTP 304状态码来减少同一客户端对同样内容的多次读取。
  • 如果不对这个文件内容进行管理,将导致硬盘空间溢出。如果对其管理,会添加很多的开发、运维和设计的工作,得不偿失。

总结

想清楚了再开干就是这个意思,花点时间系统的想想,想清楚了,前面多写点代码,多写点单元测试,后面少点麻烦,不用救火,也不用加班。 
吃饭去了。

再多啰嗦一句,《JUnit收费课程》的第二节的材料已经准备好了,昨晚担心自己的塞着鼻子,大家听着难受,没有录。今天好多了,晚上录一下,明天上午编辑审核,明天下午或者晚上大家应该就能看到了。


评论

# re: 病中吟之内存溢出  回复  更多评论   

2015-06-16 10:50 by imxylz
有兴趣加入世界邦么?http://www.blogjava.net/xylz/archive/2013/11/05/406019.html

# re: 病中吟之内存溢出  回复  更多评论   

2015-06-16 21:52 by Justfly Shi
@imxylz
谢谢,可惜我目前不在北京。

# re: 病中吟之内存溢出  回复  更多评论   

2015-06-29 12:16 by 好介绍
对内容溢出的介绍很不错!

# re: 病中吟之内存溢出  回复  更多评论   

2015-08-12 11:33 by 东莞服务器租用
话说中间留那么大一空白是啥意思?

只有注册用户登录后才能发表评论。


网站导航: