论坛首页 Java企业应用论坛

Java变量作用域内存

浏览 11599 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (15) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-05-10   最后修改:2010-05-10
我一直在想一个问题,做循环的时候变量在循环体内定义省内存还是变量在循环体外定义省内存,于是做了下实验:
import junit.framework.TestCase;

class HoldMemory{
	String str01="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	
	public HoldMemory(){
	}
}

public class MemoryCase extends TestCase{

	public void testname() throws Exception {
		for (int i = 0; i < 50000; i++) {
			HoldMemory holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


和下面的code进行比较:
import junit.framework.TestCase;

class HoldMemory{
	String str01="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	
	public HoldMemory(){
	}
}

public class MemoryCase extends TestCase{

	public void testname() throws Exception {
                HoldMemory holdMemory=null;
		for (int i = 0; i < 50000; i++) {
		     holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}

结果两个打印的结果是一样的,当然我是分两次运行的,不是在一一起运行的。所以感觉没有区别,可能从作用域来说作用域越小,越容易被回收吧,所以并不是变量定义在外面科学,感觉应该是定义在里面更好一些,因为生命周期短,容易被回收。
但是从CPU角度讲,可能写在外面的话,创建新变量的过程省了,是不是更加节省CPU执行单元?

另外有以下代码可以跑着看看内存什么时候被回收,你可以试试写在外面好还是写在里面好,我跑着试了试,感觉都一样:
package com.ibm.partnerworld.vic.testcase;

import junit.framework.TestCase;

class HoldMemory{
	String str01="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str02="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str03="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str04="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str05="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str06="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str07="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str08="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str09="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str10="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str11="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str12="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str13="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str14="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str15="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	
	public HoldMemory(){
		try {
			System.out.println("Created");
			Thread.currentThread().sleep(3);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
		System.out.println("I was reused!");
	}
}

public class MemoryCase extends TestCase{

	public void testname() throws Exception {
		HoldMemory holdMemory=null;
		for (int i = 0; i < 50000; i++) {
			holdMemory=new HoldMemory();
			System.out.println("total=>"+Runtime.getRuntime().totalMemory());
			System.out.println("free=>"+Runtime.getRuntime().freeMemory());
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}

   发表时间:2010-05-10  
变量的作用域如果只是在循环内,建议使用如下这种方式:
for (int i = 0; i < 50000; i++) { 
            HoldMemory holdMemory=new HoldMemory(); 
}
理由:
1. 这种用法更合理,更规范点
2. 性能上的差异,微乎其微,可以完全不用考虑
0 请登录后投票
   发表时间:2010-05-10  
基本上没有影响。循环变量是在栈上定义的,所以在循环体内外定义基本没有区别。但是从代码可读性来说,尽量缩小变量的作用域是非常重要的。另外,除非你是做嵌入系统,各个方面的资源非常紧张,否则总是这样思考不是很明智。更应该关心的代码的可读性和可维护性。
0 请登录后投票
   发表时间:2010-05-10  
首先需要清楚内存分配有堆栈和堆,就好比String s=new String("2")有几个对象的问题,s放在堆栈上,new的对象放在堆上,在循环内定义变量,变量在堆栈上出了作用域就被销毁了,而定义在外,变量出了循环没有被销毁
0 请登录后投票
   发表时间:2010-05-10  
这种小测试感觉是没什么区别,但是拿到项目中应用呢?
0 请登录后投票
   发表时间:2010-05-10  
luzl 写道
我一直在想一个问题,做循环的时候变量在循环体内定义省内存还是变量在循环体外定义省内存,于是做了下实验:
	public void testname() throws Exception {
		for (int i = 0; i < 50000; i++) {
			HoldMemory holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


和下面的code进行比较:
	public void testname() throws Exception {
                HoldMemory holdMemory=null;
		for (int i = 0; i < 50000; i++) {
		     holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


Java是编译型语言不是解释型语言。
上面两段代码生成的字节码,对于方法testname() 而言,其局部变量都是3个:this、i、holdMemory,
即使看上去“HoldMemory holdMemory”是在循环体内声明的,holdMemory变量也仍然只有一个。

这两段代码生成的字节码的唯一区别是 第一段代码前面多了局部变量的初始化操作。

第一段代码对应的字节码:


第二段代码对应的字节码:


  • 大小: 35.7 KB
  • 大小: 33.4 KB
0 请登录后投票
   发表时间:2010-05-10  
楼上查看字节码的工具是什么啊.能介绍一下不?
看上去好像是netbeans的感觉啊
0 请登录后投票
   发表时间:2010-05-10  
sswh 写道
luzl 写道
我一直在想一个问题,做循环的时候变量在循环体内定义省内存还是变量在循环体外定义省内存,于是做了下实验:
	public void testname() throws Exception {
		for (int i = 0; i < 50000; i++) {
			HoldMemory holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


和下面的code进行比较:
	public void testname() throws Exception {
                HoldMemory holdMemory=null;
		for (int i = 0; i < 50000; i++) {
		     holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


Java是编译型语言不是解释型语言。
上面两段代码生成的字节码,对于方法testname() 而言,其局部变量都是3个:this、i、holdMemory,
即使看上去“HoldMemory holdMemory”是在循环体内声明的,holdMemory变量也仍然只有一个。

这两段代码生成的字节码的唯一区别是 第一段代码前面多了局部变量的初始化操作。

第一段代码对应的字节码:


第二段代码对应的字节码:



用你这个就很好理解为什么两个在内存的占用上是一样的了,请教一下你是怎么看字节码的?
1 请登录后投票
   发表时间:2010-05-11  
lbfhappy 写道
楼上查看字节码的工具是什么啊.能介绍一下不?
看上去好像是netbeans的感觉啊

强烈要求公布一下
0 请登录后投票
   发表时间:2010-05-11  
luzl 写道
我一直在想一个问题,做循环的时候变量在循环体内定义省内存还是变量在循环体外定义省内存,于是做了下实验:
import junit.framework.TestCase;

class HoldMemory{
	String str01="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	
	public HoldMemory(){
	}
}

public class MemoryCase extends TestCase{

	public void testname() throws Exception {
		for (int i = 0; i < 50000; i++) {
			HoldMemory holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


和下面的code进行比较:
import junit.framework.TestCase;

class HoldMemory{
	String str01="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	
	public HoldMemory(){
	}
}

public class MemoryCase extends TestCase{

	public void testname() throws Exception {
                HoldMemory holdMemory=null;
		for (int i = 0; i < 50000; i++) {
		     holdMemory=new HoldMemory();
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}

结果两个打印的结果是一样的,当然我是分两次运行的,不是在一一起运行的。所以感觉没有区别,可能从作用域来说作用域越小,越容易被回收吧,所以并不是变量定义在外面科学,感觉应该是定义在里面更好一些,因为生命周期短,容易被回收。
但是从CPU角度讲,可能写在外面的话,创建新变量的过程省了,是不是更加节省CPU执行单元?

另外有以下代码可以跑着看看内存什么时候被回收,你可以试试写在外面好还是写在里面好,我跑着试了试,感觉都一样:
package com.ibm.partnerworld.vic.testcase;

import junit.framework.TestCase;

class HoldMemory{
	String str01="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str02="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str03="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str04="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str05="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str06="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str07="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str08="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str09="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str10="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str11="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str12="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str13="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str14="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	String str15="12111111111111111111111111111111111111111111111111111111111111111111111111111111111";
	
	public HoldMemory(){
		try {
			System.out.println("Created");
			Thread.currentThread().sleep(3);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
		System.out.println("I was reused!");
	}
}

public class MemoryCase extends TestCase{

	public void testname() throws Exception {
		HoldMemory holdMemory=null;
		for (int i = 0; i < 50000; i++) {
			holdMemory=new HoldMemory();
			System.out.println("total=>"+Runtime.getRuntime().totalMemory());
			System.out.println("free=>"+Runtime.getRuntime().freeMemory());
		}
		System.out.println(Runtime.getRuntime().freeMemory());
		
	}
}


在外面·那么只有一个引用
里面·引用的个数就是循环的次数
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics