虽然Java的垃圾回收和当前高配置的服务器可以让程序员大部分时间忘掉OutOfMemoryError的存在,但是访问量增大后频繁的GC会额外消耗CPU (使用top查看结果为us值高),系统响应速度下降,积压的请求又会占用更多内存从而恶性循环,严重时可能导致系统不断Full GC造成应用停顿。

优化内存的使用可从以下几方面着手:

一、节流
1 使用单例模式

单例模式是开发者最早接触并使用的设计模式之一,尽管写代码的时候可能还不知道用了设计模式。简单来说就是构造函数private化,通过静态方法获得唯一实例。因为其特性,对于某些场景例如每次请求都要使用无状态工具类的检验方法,使用单例模式可以大量节省创建新对象的开销。

[java] view plaincopy print?
  1. public class Singleton {
  2. private Singleton() {}
  3. private static Singleton instance = new Singleton();
  4. public static Singleton getInstance() {
  5. return instance;
  6. }
  7. public void doSomething() { }
  8. }
2 缓存常用对象

简单来说就是按一定特征创建"对象缓存池",使用集合类保存已创建的对象,当有相同特征的对象申请时,使用缓存池中现有的对象代替通过 new关键字重新创建。

[java] view plaincopy print?
  1. public class BigObjectPoolTest {
  2. public static void main(String[] args) {
  3. long start = System.nanoTime();
  4. for(int i = 0; i < 10000; i++) {
  5. BigObjectPool.getBigObject("xxx", true);
  6. }
  7. System.out.println("使用缓存池耗时" + TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS) + "毫秒");
  8. start = System.nanoTime();
  9. for(int i = 0; i < 10000; i++) {
  10. BigObjectPool.getBigObject("xxx", false);
  11. }
  12. System.out.println("不使用缓存池耗时" + TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS) + "毫秒");
  13. }
  14. }
  15. class BigObjectPool {
  16. private static Map<String, BigObject> map = new HashMap<String, BigObject>();
  17. static {
  18. map.put("xxx", new BigObject("xxx"));
  19. map.put("yyy", new BigObject("yyy"));
  20. }
  21. public static BigObject getBigObject(String key, boolean usePool) {
  22. if(usePool) {
  23. BigObject bo = map.get(key);
  24. if(bo == null) {
  25. bo = new BigObject(key);
  26. }
  27. return bo;
  28. } else {
  29. return new BigObject(key);
  30. }
  31. }
  32. }
  33. class BigObject{
  34. private String name;
  35. private byte[] data = new byte[1024 * 1024];
  36. public BigObject(String name) { this.name = name; }
  37. }

以-Xms32m -Xmx32m -Xloggc:d:/gc.log 参数运行

[java] view plaincopy print?
  1. 使用缓存池耗时3毫秒
  2. 不使用缓存池耗时998毫秒

(查看gc.log,可以观察到不使用缓存池触发Minor GC 1000次以上)

实际业务中通常使用EhCache等框架代替自己实现缓存池。

与这种实现原理相似的也有一个设计模式:享元模式,区别是享元模式更关注类设计结构上的优化,对上下文环境的设计也做了明确定义。

3 避免设计过大的对象

如果业务模型中要求的类的属性和方法都非常多,可以尝试将其拆分成多个小类,再通过合成/聚合模式组装成一个大类,这也符合设计模式的优化思想。甚至可以结合上面的对象缓存池的方式将其中一部分内容缓存化。

[java] view plaincopy print?
  1. class Composition {
  2. private BigObject bigObject = null;
  3. private int id;
  4. public void setBigObject(BigObject bigObject) {
  5. this.bigObject = bigObject;
  6. }
  7. public Composition(int id) {
  8. this.id = id;
  9. }
  10. }
[java] view plaincopy print?
  1. Composition c = new Composition(1);
  2. c.setBigObject(BigObjectPool.getBigObject("xxx", true));
4 一些小技巧

使用StringBuilder代替用+号连接字符串

尽量使用int, long等基本类型代替Integer, Long包装对象

合理利用SoftReference和WeakReference

二、开源 - 调整虚拟机参数

一般设置 java -server -Xms2048m -Xmx2048m -XX:PermSize=256m  -XX:MaxPermSize=256m

-Xms和-Xmx决定java堆区可使用的内存最小值和最大值,通常设为相同的值,避免运行期间反复的重新申请内存。如果出现OutOfMemoryError: Java heap space,则在硬件允许的情况下临时调大-Xmx,为排查问题和优化代码争取时间。

-XX:PermSize和-XX:MaxPermSize决定永久代可用空间大小,存放class和meta信息,通常设置为相同的值。如果出现OutOfMemoryError: PermGen space,说明加载的类和jar文件过多,可以调大这两个参数值。

如果web容器下有多个应用引用了相同的第三方jar文件,可以转移到容器的共享目录。

另一个重要参数是-Xmn,决定堆区新生代的大小,通常占-Xmx的比值设置为1/4到1/3。如果业务中有大量体积大且生命周期很短的对象创建需求,可适当调大新生代空间以利于失效对象在新生代中被回收。

此外,可通过参数设置回收算法:

–XX:+UseSerialGC
–XX:+UseParallelGC
–XX:+UseParallelOldGC
–XX:+UseConcMarkSweepGC

回收算法的选择和对比需要较大的篇幅介绍,这里不做详细的解释。通常来说,对于响应时间优先的web应用,ConcMarkSweepGC(CMS)是个不错的选择。

需要注意的是,经过几代发展后,JVM对内存管理已经做的非常好。如果不是有明确的证据证明JVM的默认选择不合理,就没必要做过多细节的调整设置。调整后,可通过-XX:+PrintGCDetails -XX:+PrintGCTimeStamps等参数输出GC信息进行比对,优化的首要目标是减少Full GC次数和时间。

参考资料: 分布式java应用基础与实践

转载于:https://www.cnblogs.com/sa-dan/p/6837151.html

开发高性能JAVA应用程序基础(内存篇)相关推荐

  1. java 内存管理_高性能Java代码之内存管理

    本文通过几个方面,来介绍Java代码的内存管理. 有的代码,GC根本就回收不了,直接系统挂掉.GC是一段程序,不是智能,他只回收他认为的垃圾,而不是回收你认为的垃圾. GC垃圾回收: Grabage ...

  2. 应用程序基础知识:activity和intent——Android开发秘籍

    应用程序基础知识:activity和intent --Android开发秘籍 v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#defaul ...

  3. Java开发高性能网站需要关注的事

    转自:http://www.javabloger.com/java-development-concern-those-things/ 近期各家IT媒体举办的业内技术大会让很多网站都在披露自己的技术内 ...

  4. 使用Java开发高性能网站需要关注的那些事儿

    近期各家IT媒体举办的业内技术大会让很多网站都在披露自己的技术内幕与同行们分享,大到facebook,百度,小到刚起步的网站.facebook,百度之类的大型网站采用的技术和超凡的处理能力的确给人耳目 ...

  5. Java进阶 JVM 内存与垃圾回收篇(一)

    JVM 1. 引言 1.1 什么是JVM? 定义 Java Vritual Machine - java 程序的运行环境(Java二进制字节码的运行环境) 好处 一次编译 ,到处运行 自动内存管理,垃 ...

  6. 构建Java开发高性能网站需要关注的事儿

    近期各家IT媒体举办的业内技术大会让很多网站都在披露自己的技术内幕与同行们分享,大到facebook,百度,小到刚起步的网站.facebook,百度之类的大型网站采用的技术和超凡的处理能力的确给人耳目 ...

  7. 第一篇:微信公众平台开发实战Java版之了解微信公众平台基础知识以及资料准备...

    相信很多人或多或少听说了微信公众平台的火热.但是开发还是有一点门槛,鉴于挺多朋友问我怎么开发,问多了,自己平时也进行以下总结. 所以下面给大家分享一下我的经验: 第一部分   介绍微信公众号的一些简单 ...

  8. 并发型服务器响应方式,基于Java NIO 开发高性能并发型服务器程序的研究

    基于Java NIO 开发高性能并发型服务器程序的研究 第8卷%第5期 软件导刊 2009年5月SoftwareGuide Vol.8No.5May.2009 基于JavaNIO开发高性能并发型服务器 ...

  9. 开发内功修炼内存篇汇总

    最近终于抽空把内存篇更新完了,我分享出来的这些问题,其实都是我之前没有搞的特别明白的困惑.刚刚开始的时候,可能就是在我脑子里蹦出的一个疑问,比如内存随机IO会比顺序IO慢吗? 为了解开这个疑惑,我曾经 ...

最新文章

  1. ServletResponse-中文名的下载
  2. 自制程序清除系统垃圾文件
  3. BAT技术专家的4个考核点!
  4. arcmap shp导出cad无反应_地图数据获取|2、CAD地图获取
  5. 如何在Membership中实现修改密码的功能
  6. MySQL Commons
  7. 中国人数学好,数学思维差?
  8. TypeError: 'module' object is not callable (pytorch在进行MNIST数据集预览时出现的错误)
  9. java big5转换为gbk_简体繁体转换代码(Big5-GB | GBK简体-GBK繁体)
  10. VGA分辨率无法识别或错误通过添加自定义配置参数正确显示(Ubuntu/Windows)
  11. 初级java程序员要求_java初级程序猿需要具备的能力?
  12. android MediaPlayer m3u8 播放
  13. 科研必备之图像局部区域放大——画中画形式
  14. [转] JavaScript 骚操作
  15. python cv2 轮廓的包络 面积_Python科学计算——检包络与去包络
  16. 面试题:群聊消息的已读未读设计
  17. php 2个数组并集,php中数组的并集、交集和差集函数介绍_PHP教程
  18. 剥茧抽丝,细数模块化的前世今生
  19. 扫雷游戏(基础版本)
  20. 【C#】C#调用Bartender模板打印

热门文章

  1. JZOJ 5398. 【NOIP2017提高A组模拟10.7】Adore
  2. SPI/I2S调试心得与经验总结
  3. python图像锐化_opencv实现图片模糊和锐化操作
  4. python计算两个数乘积_如何用PYTHON使两个数字总和变成乘积
  5. 计算机怎么恢复上一步,电脑怎么还原系统 电脑还原系统步骤盘点
  6. python简单体育竞技模拟_Python程序设计思维练习---体育竞技分析-阿里云开发者社区...
  7. Tex 表格注释实例
  8. 线段树(假)练习题一(学校OJ的题)
  9. freebsd mysql57_Freebsd7.2下Ports安装PHP5、MySql5.4、Apache22
  10. python相同key合并value_Python快速入门最需掌握的4个知识点