读书人

Java优化编程札记内存管理

发布时间: 2013-07-01 12:33:04 作者: rapoo

Java优化编程笔记——内存管理
1. 垃圾回收
JVM运行环境中垃圾对象的定义:
一个对象创建后被放置在JVM的堆内存(heap)中,当永远不再引用这个对象时,它将被JVM在堆内存(heap)中回收。被创建的对象不能再生,同时也没法通过程序语句释放它们。

不可到达的对象被JVM视为垃圾对象,JVM将给这些对象打上标记,然后清扫回收它们,并将散碎的内存单元收集整合。

JVM管理的两种类型的内存:
堆内存(heap),主要存储程序在运行时创建或实例化的对象与变量。
栈内存(stack),主要存储程序代码中声明为静态(static)(或非静态)的方法。

堆内存(heap)通常情况下被分为两个区域:新对象(new object)区域与老对象(old object)区域。

新对象区域:
又可细分为Eden区域、From区域与To区域。
Eden区域保存新创建的对象。当该区域中的对象满了后,JVM系统将做可达性测试,主要任务是检测有哪些对象由根集合出发是不可到达的,这些对象就可被JVM回收,且将所有的活动对象从Eden区域拷到To区域,此时有一些对象将发生状态交换,有的对象就从To区域被转移到From区域,此时From区域就有了对象。
该过程执行期间,JVM的性能非常低下,会严重影响到正在运行的应用的性能。

老对象区域:
在老对象区域中的对象仍有一个较长的生命周期。经过一段时间后,被转入老对象区域的对象就变成了垃圾对象,此时它们被打上相应的标记,JVM将自动回收它们。
建议不要频繁强制系统做垃圾回收,因为JVM会利用有限的系统资源,优先完成垃圾回收工作,致使应用无法快速响应来自用户端的请求,这样会影响系统的整体性能。

2. JVM中对象的生命周期
对象的整个生命周期大致分为7个阶段:创建(creation)、应用(using)、不可视(invisible)、不可到达(unreachable)、可收集(collected)、终结(finalized)、释放(free)。

1) 创建阶段
系统通过下面步骤,完成对象的创建:
a) 为对象分配存储空间
b) 开始构造对象
c) 递归调用其超类的构造方法
d) 进行对象实例初始化与变量初始化
e) 执行构造方法体

在创建对象时的几个关键应用规则:
? 避免在循环体中创建对象,即使该对象占用内存空间不大
? 尽量及时使对象符合垃圾回收标准
? 不要采用过深的继承层次
? 访问本地变量优于访问类中的变量

关于“在循环体中创建对象”,如下方式会在内存中产生大量的对象引用,浪费大量的内存空间,增大了系统做垃圾回收的负荷:

    class CleanUpThread extends Thread {        private ObjectPool pool;        private long sleepTime;                CleanUpThread(ObjectPool pool, long sleepTime) {            this.pool = pool;            this.sleepTime = sleepTime;        }            public void run() {            while (true) {                try {                    sleep(sleepTime);                } catch (InterruptedException e) {                    …// 相应处理                }                pool.cleanUp();            }        }    }


7. transient变量
在做远程方法调用(RMI)类的应用开发时,应该会遇到transient变量与Serializable接口,之所以要对象实现Serializable接口,是因为这样就可以从远程环境以对象流的方式,将对象传递到相应的调用环境中,但有时这些被传递的对象的一些属性并不需要被传递,因为这些数据成员对于应用需求而言是无关紧要的,那么这些属性变量就可被声明为transient。被声明为transient的变量是不会被传递的,这样能节约调用方的内存资源,减少网络开销,提高系统性能。这个transient变量所携带的数据量越大(如数据量较大的数组),其效用越大。

8. JVM内存参数调优
-XX:NewSize,设置新对象成产堆内存(set new generation heap size)
通常该选项数值为1024的整数倍且大于1MB。取值规则为,取最大堆内存(maximum heap size)的1/4。

-XX:MaxNewSize,设置最大新对象生产堆内存(set maximum new generation heap size)
其功用同-XX: NewSize。

-Xms,设置堆内存池的最小值(set minimum heap size)
要求系统为堆内存池分配内存空间的最小值。通常该选项数值为1024的整数倍且大于1MB。取值规则为,取与最大堆内存(-Xmx)相同的值,以降低GC的频度。

-Xmx,设置堆内存池的最小值(set maximum heap size)
要求系统为堆内存池分配内存空间的最大值。通常该选项数值为1024的整数倍且大于1MB。取值规则为,取与最大堆内存(-Xms)相同的值,以降低GC的频度。

例:
java XX:NewSize=128m XX:MaxNewSize=128m Xms512m Xmx512m MyApp

9. Java程序设计中有关内存管理的其他经验
1) 尽早释放无用对象的引用,加速GC的工作
2) 尽量少用finalize()。finalize()是Java给程序员提供一个释放对象或资源的机会,但会加大GC的工作量
3) 对常用到的图片,可采用SoftReference
4) 注意集合数据类型,包括数组、树、图、链表等数据结构,它们对GC来说,回收更复杂。另外,注意一些全局变量、静态变量,它们易引起悬挂对象,造成内存浪费
5) 尽量避免在类的默认构造器中创建、初始化大量的对象,防止在调用其子类的构造器时造成不必要的内存资源浪费
6) 尽量避免强制系统做GC(通过显式调用System.gc()),增长系统GC的最终时间,降低系统性能
7) 尽量避免显式申请数组空间,当不得不显式申请时,尽量准确估计出其合理值
8) 在做远程方法调用(RMI)类应用开发时,尽量使用transient变量
9) 在合适的场景下使用对象池技术以提高系统性能,缩减系统内存开销,但需注意对象池的尺寸不宜过大,及时清除无效对象释放内存资源

读书人网 >编程

热点推荐