您的位置:首页 > 编程语言 > Java开发

java编程优化-内存管理

2010-11-28 22:03 260 查看

[ 2010-05-13 19:34:32.0 | 作者: 随想 类别: 基础强化 ] 来源:原创 浏览 2311

labels:java编程优化-内存管理 强引用 软引用 弱引用 java中的析构方法 jvm中对象的生命周期 垃圾回收

内存管理

垃圾回收,Jvm中的垃圾对象定义:
理解1:一个对象创建后放置在jvm的堆内存中.当永远不再引用这个对象时,他将被jvm在堆内存中回收,被创建对象不能再生,
同事也没办法通过程序语句释放他们.

理解2:当对象在jvm运行空间中无法通过根集合到达时,这个对象就被称作垃圾对象.
根集合是由类中的静态引用域与本地引用组成的.

jvm中对象的生命周期,分为7个阶段
创建阶段,应用阶段,不可视阶段,不可到达阶段,可收集阶段,终结阶段,释放阶段.

创建对象的几个规则:
(1) 避免在循环体中创建对象,即使该对象占用内存空间不大.
for(int i = 0; i < 10000; i++){
Object obj = new Object();	//应当避免
System.out.println("obj "+obj);
}

Object o = null;
for(int i = 0; i < 100000; i++){
o = new Object();	//仅在内存中保存一份对象的引用,可取
System.out.println("obj "+o);
}
-----------------------------------------------------------------------------
public class demo{
private List list = new ArrayList();
public demo(){
list = new ArrayList();		//将对象初始化了2次,大大影响效率
}
}

(2) 尽量及时使对象符合垃圾回收标准
不要采用过深的继承层次
访问本地变量优于访问类中变量

强引用
jvm内存管理器从跟引用集合出发遍寻堆中所有到达对象的路径.当到达某对象的任意路径都不含有引用对象时.被称为强引用.

软引用
主要特点是具备较强的引用功能,只有当内存不够的时候,才会回收这类内存,因此在内存足够的时候,他们通常不被回收.
另外,这些引用对象还能保证java跑出OutOfMemory异常之前,被设置成null.它可以用于实现一些常用的资源缓存,
实现Cache的功能.保证最大限度的使用内存不引起OutOfMemory.
public static void main(String[] args) {
A1 a1 = new A1();
//使用a1
System.out.println(a1.c);
System.out.println(a1);
//使用完a1 将它设置为soft引用类型,并且释放强引用
java.lang.ref.SoftReference sr = new java.lang.ref.SoftReference(a1);
a1 = null;
System.out.println(a1);
//下次使用的时候
if(sr != null){
a1 = (A1) sr.get();
}else{
//GC 由于低内存,已经释放a1 因此需要重新装在
a1 = new A1();
sr = new java.lang.ref.SoftReference(a1);
}
System.out.println(a1);
}

弱引用
对象与Soft引用对象的最大不同就在于,gc在进行回收时,需要通过算法检查是否回收soft引用对象,
而对weak引用对象,gc总是进行回收,weak引用对象更容易,更快的呗gc回收.虽然,gc在运行时一定回收
weak对象,但是复杂关系的weak对象群常常需要好几次gc的运行才能完成.weak引用对象常常用于
map结构中.引用占用内存空间较大的对象.一旦该对象的强引用为null时,对这个对象引用就不存在了,
gc能够快速地回收该对象空间.
public static void main(String[] args) {
Demo demo = new Demo();
//使用....
System.out.println(demo+" "+demo.c);
//...使用完事将它设置为weak引用类型,并释放强引用
java.lang.ref.WeakReference wr = new java.lang.ref.WeakReference(demo);
demo = null;

System.out.println("demo 没了 "+demo);

//...下次使用的时候
if(wr != null){
demo = wr.get();
}else{
demo = new Demo();
}
//再次使用
System.out.println(demo+" "+demo.c);

}

虚引用
用途较少,主要用于辅助finalize函数的使用.

强调:
在实际程序设计中一般很少使用弱引用和虚引用,使用软件的情况较多,这是因为软件引用可以加上jvm
对内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题产生

不可视阶段
当一个对象处于不可视阶段,说明我们在其他区域的代码中已经不可以在引用它了,
强引用已经消失.例如,本地变量超出了可视范围.
public void pore(){
if(true){
Object object = new Object();
object.getClass();
}
if(true){
//这个区域对于object对象来说已经是不可视的了.
//因此下面的代码在编译时就会引发错误
object.getClass();
}
}
如果一个对象在使用完之后,而且在其可视范围区域不在使用,此时应该主动将其设置为空,
可以在object.getClass();下行加上object = null;这样一行代码强制将object对象设置为空值.
这样做的意义在于,可以帮jvm及时地发现这个垃圾对象,并且可以及时地回收该对象所占用
的系统资源.

数组空间的申请分为显示申请and隐式申请.
public static void main(String[] args) {
int[] as = new int[1024];
//上面这行代码就是显示的相系统一次性的申请了大小为1kb的整数类型的内存空间
//如果实际需要放入的字眼不足1024 就会浪费资源应该尽可能的用完就马上体现jvm回收

String[] strs = new String[222222];
SoftReference sf = new SoftReference(strs);
//用完.....
strs = null;
}

不要提前创建对象
尽量在需要的时候在创建对象,重复的分配,构造对象可能会因为垃圾回收做额外的工作,
降低性能.
void fn(){
int i;
A a = new A();
// 类A的对象a被创建
//在判断语句之外并没有应用过a.
if(true){
// 类A的对象a再次应用
a.findMethod();
...
}
...
}

应该这么写
void fn(){
int i;
...
if(true){
A a = new A();
a.findMethod();
...
}
}

而在java语言中只有构造的概念,却没有析构的概念,这是因为理论上jvm负责对象的
析构方法,由于在java应用中开发的所有类都为Object的子类,因此用户类都从Object
因此finalize的最后一句通常是super.finalize().通过这种方式买我们可以实现从下到上
<FONT color="#5c585a" face=""">finalize调用.即先释放自身在主机往上释放.
package com.iwgod.chapter02.finalize;

public class A {
Object a = null;
public A(){
a = new Object();
System.out.println("构建A对象");
}
protected void destory(){
a = null;
System.out.println("释放a对象");
}
protected void finalize() throws Throwable{
destory();
super.finalize();	//递归调用超类的finalize方法
}
}

package com.iwgod.chapter02.finalize;

public class B extends A {
String b = null;
public B(){
b = "aa";
System.out.println("构建B对象");
}
protected void destory(){
b = null;
System.out.println("释放b对象");
super.destory();
}
protected void finalize() throws Throwable{
destory();
super.finalize();
}

}

package com.iwgod.chapter02.finalize;

public class C extends B {
Object c = null;
public C(){
c = new Object();
System.out.println("创建C对象");
}
protected void destory(){
c = null;
System.out.println("释放c对象");
super.destory();
}
protected void finalize() throws Throwable{
destory();
super.finalize();
}
}

package com.iwgod.chapter02.finalize;

public class Test {

/**
* @param args
* @throws Throwable
*/
public static void main(String[] args) throws Throwable {
// TODO Auto-generated method stub
C c = new C();
c.destory();
}
/**
* 注意到test类中实例化C对象的时候,其构造器产生了递归调用,并且是由几类开始
* 一次调用,初始化成员对象,而当调用c类的destory方法时系统通用产生了递归调用
* 但调用的顺序恰好相反.释放资源由子类开始,
* 由此可见我们在设计类时尽量避免在类的默认构造器中创建,初始化大量的对象,防止在调用其自身的构造器
* 时造成不必要的内存浪费,因为即使我们没有像调用父类的构造器创建大量无用的对象,但是喜用都会自动去
* 创建它们,而这些操作都是隐含的
*/

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: