Java内存分析


java内存分析
http://blog.csdn.net/lidaasky/article/details/7931560
java中,除了8种基本类型,其他都是引用类型。

局部变量:方法体内声明的变量,包括形参都是局部变量方法体外。
成员变量:类内声明的变量为成员变量。


由图可以看出,执行步骤:
1、从硬盘中提取代码到内存中。
2、代码存放在代码段;局部变量和基本数据类型存放于栈(Stack);引用类型存放于堆(Heap)中;静态变量、字符串存放于数据段。

内存分析


* 一维数组例如一维数组的初始化
[java]
1. int [] s;s=new int [5];
* 先是在栈中声明s:


在内存中是s指向了堆内的值:




如果数组的项是引用类型,如下

1. public class Test{
 2. public static void main(String args[]){
 3. Date []days;
 4. days=new Date[3];
 5. for (int i=0;i<3;i++){
 6. days[i]=new Date(2004,4,i+1);
 7. }
 8. }
 9. }
 10. class Date{
 11. int year;int month;int day;
 12. Date(int y;int m;int d){
 13. year=y;
 14. month=m;
 15. day=d;
 16. }
 17. } 


执行Date [] days;在栈中给days分配空间:

执行days= new Date[3];在堆中给days分配三个位置,内容为空,days指向这三个位置:


执行循环后,每个days项再指向堆中分配的时间位置:

二维数组二维数组可以看成以数组为元素的数组。例如:
int a[][]={{1,2},{3,4,5,6},{7,8,9}};

内存回收

栈里面的内存,函数执行完后消失,而堆里面的内存,需要垃圾回收机制回收,不一定马上消失。
实参与局部变量同等对待;函数返回值也会在栈里面临时存放,函数就执行完也就会删除,调用完毕后内存回收,但是只分配空间,没有名字。

构造函数

1. Public class Person{
 2. int id;
 3. int age=20;
 4. Person(int _id,int _age){
 5. id=_id;
 6. age=_age;
 7. }
 8. Pubic static void main(String [] args){
 9. Person tom=new Person(1,25);
 10. }
 11. } 


在栈中分配一个空间为tom,用于new出对象:
构造函数的值也放到栈中:
执行new时
把栈中的值赋给堆中new出来的tom对象:

执行完毕后,方法中的局部变量在栈中所占空间被收回。
this指针
我们都知道this指向的是对象本身,以下这张图可以形象的看出,this是如何指向自身:
static变量静态变量,分配空间时,位于的是数据段,而并非堆和栈中。
  • static变量

    静态变量,分配空间时,位于的是数据段,而并非堆和栈中。


super关键字
1. class FatherClass {
 2. public int value;
 3. public void f(){
 4. value = 100;
 5. System.out.println
 6. ("FatherClass.value="+value);
 7. }
 8. }
 9. class ChildClass extends FatherClass {
 10. public int value;
 11. public void f() {
 12. super.f();
 13. value = 200;
 14. System.out.println
 15. ("ChildClass.value="+value);
 16. System.out.println(value);
 17. System.out.println(super.value);
 18. }
 19. }
 20. public class TestInherit {
 21. public static void main(String[] args) {
 22. ChildClass cc = new ChildClass();
 23. cc.f();
 24. }
 25. } 


super指向的是该对象的类继承的类的对象,如下



继承

1. class Person {
 2. private String name;
 3. private int age;
 4. public void setName(String name) {
 5. this.name=name;
 6. }
 7. public void setAge(int age) {
 8. this.age=age;
 9. }
 10. public String getName(){
 11. return name;
 12. }
 13. public int getAge(){
 14. return age;
 15. }
 16. }
 17. class Student extends Person {
 18. private String school;
 19. public String getSchool() {
 20. return school;
 21. }
 22. public void setSchool(String school) {
 23. this.school =school;
 24. }
 25. }
 26. public class Test {
 27. public static void main(String arg[]){
 28. Student student = new Student();
 29. student.setName("John");
 30. student.setAge(18);
 31. student.setSchool("SCH");
 32. System.out.println(student.getName());
 33. System.out.println(student.getAge());
 34. System.out.println(student.getSchool());
 35. }
 36. } 


由图可以看出,继承的类实例化时,其内部包含其父类的对象,



实现接口内存分析

1. interface Singer{
 2. public void sing();
 3. public void sleep();
 4. }
 5. class Student implements Singer{
 6. private String name;
 7. Student(String name){
 8. this.name=name;
 9. }
 10. public void study(){
 11. System.out.println("studying");
 12. }
 13. public void sing(){
 14. System.out.println("singing");
 15. }
 16. public void sleep(){
 17. System.out.println("sleeping");
 18. }
 19. public String getName(){
 20. return name;
 21. }
 22. }
 23. public class Test{
 24. public static void main(String args[]){
 25. Singer S1=new Student("le");
 26. s1.sing();
 27. s1.sleep();
 28. }
 29. } 


New出来的Student("le"),应该有sing();sleep();study();getName(),但是由于定义的是Singer S1,所以s1只能访问New出来的Student中的sing和sleep方法。




以前看设计模式,对Interface xx=new Object();及类似的语句理解非常模糊,类似这样的问题内存分析可以更直观的展示出其原理。本文简单介绍了函数、类、对象的内存分析,掌握这些可以更深刻的掌握面向对象常见的继承、实现、构造、多态等。


Java内存分配是Java的核心技术之一
◆寄存器:我们在程序中无法控制
◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
◆堆:存放用new产生的数据
◆静态域:存放在对象中用static定义的静态成员
◆常量池:存放常量
◆非RAM存储:硬盘等永久存储空间


java内存分配中的栈:
当一段代码中定义一个变量时,java就在栈中为这个变量分配内存空间,当该变量退出作用域后,java会自动释放掉该变量所分配的内存空间,该内存空间可以立即被另作他用。
java内存分配中的堆:
堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机的自动垃圾回收机制来管理。

--堆:Heap
--栈:Stack
---new一个对象时候存放在堆中
---变量存放在栈中
如:Student studnet = new Student() //student是对象句柄(引用)




栈的优势是,存取速度快,仅次于寄存器,栈中数据可以共享,缺点是栈的数据大小和生存期都必须确定,缺乏灵活性。
栈中主要存放一些基本类型的变量数据(int, short, long, byte, float, double, boolean, char)和对象句柄(引用)。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。







注意:
String str = "aaa";
String str = new String("aaa");
他们内存分配区别?

前者是在栈中,后者是在堆中创建对象,分配内存空间,其引用在栈中

String是一个特殊的包装类数据。可以用:
String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。

String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。
因此用第一种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值