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

2015.09.01 Java 学习笔记—内存分析精华

2015-09-02 08:47 633 查看
掌握以下内容足以够以后学习所用,很好,很详细,一定吃透

内存分析基础知识

栈内存和堆内存

栈内存:保存堆内存对应的地址数据,如果想要简单的理解,就将说明为对象的名称.

堆内存:保存真正有用的数据:指的是对象的属性内容,每一块堆内存都是一块内存地址的信息.



关键字new相当于计算机在内存之中自动开辟一块新的堆内存空间, 开辟完之后分配的是类里属性的默认值

对象只有实例化之后才可以使用,如果使用了未实例化的对象,一定会出现NullPointerExceptiong,而此异常只要是你从事开发工作,一定会一直陪伴这你, 特别需要提醒的是,每当使用了关键字new操作的时候都会分配新的堆内存空间,所以如果现在实例化了两个对象呢?



在日后的开发中,需要开辟新的堆内存空间,那么就是用关键字new

对象的真实数据都保存在堆内存之中,所以所谓的引用关系,指的就是同一块堆内存空间被不同的栈所指向





所以在实际的开发当中尽量不要产生无用的对内存空间,所有无用的堆内存空间最终都会被gc定期回收

2.成员变量和局部变量

成员变量包含:实例变量和类变量.(系统会为成员变量执行默认初始化)

实例变量:从有实例开始,实例变量就存在了,实例被销毁,实例变量销毁.

类变量:从有类开始,类变量就存在,一个jvm 里类信息只有一个,每个jvm 最多值加载一个类一次,系统就为该实例分配一块内存

Java程序不允许直接访问堆内存中的对象,只能通过该对象的引用操作该对象

只要你用这个类声明变量,或者创建实例或者调用这个类的静态方法或静态field都是用到了这个类

局部变量必须由程序员来初始化,系统不会对局部变量初始化,局部变量存放在相应方法栈中

先掌握一段简单程序内存分析

package com.buaa.day3;
/*执行详解:
* Test test = new Test();
* 首先在main方法栈内定义了一个局部变量test,
* 接着在堆内存里产生Test对象,局部变量test指向此对象
* 接着int date = 9;
* 在main方法栈中创建局部变量 date 值为9
*
************************************************
*
* BirthDate d1= new BirthDate(7,7,1970);
* 首先BirthDate d1,在stack中创建局部变量d1 ,
* 接着public BirthDate(int d, int m, int y) {day = d;   month = m;  year = y;  },
* 在stack里临时产生局部变量 d, m, y
* 接着new BirthDate(7,7,1970),将参数传给在堆内存创建BirthDate对象,局部变量 d, m, y消失
* 接着d1指向BirthDate对象(即d1存了可以找到BirthDate对象在堆内存的地址)
*
************************************************
*
* test.change1(date);
* i 的值的变化是先变成9,然后继续执行变成1234,但是由于i是局部变量,当方法执行结束以后i的值自动消失,
* 所以date的值依然是9没有改变
*
************************************************
*test.change2(d1);
*目的是为了改变d1指向堆内存里的值
*首先test.change2(d1);把d1传进来,d1的值传给处在stack里的局部变量b,b指向了d1指向的堆内存对象值。
*接着
*public void change2(BirthDate b) {//b此时是局部变量,规定传入的参数必须是BirthDate的一个引用
*b = new BirthDate(22,2,2004);//创建对象后b不指向d1对象的内存堆,指向对象b 的内存堆
*方法调用完毕时,b这个局部变量消失,指向对象的引用就消失了,堆内存里22,2,2004内容无栈指针,所以会被垃圾回收机制回收
*故不能达到目的}
*************************************************
*
*test.change3(d2);
*public void change3(BirthDate b) {b.setDay(22);} 局部变量b指向了d2指向的堆内存
*接着调用public void setDay(int d) {day = d;}此时在方法栈里产生d局部变量,将d2堆内存里的day的值传参为22,此时实现改变堆内存的对象的值
*
*
*
* */
public class Test{
public static void main(String args[]){

Test test = new Test();
int date = 9;
BirthDate d1= new BirthDate(7,7,1970);
BirthDate d2= new BirthDate(1,1,2000);
test.change1(date);
test.change2(d1);
test.change3(d2);
System.out.println("date=" + date);
d1.display();
d2.display();
}

public void change1(int i){i = 1234;}

public void change2(BirthDate b) {b = new BirthDate(22,2,2004);}

public void change3(BirthDate b) {b.setDay(22);}
}

class BirthDate {
private int day;
private int month;
private int year;

public BirthDate(int d, int m, int y) {day = d; month = m; year = y; }

public void setDay(int d) {day = d;}

public void setMonth(int m) {month = m;}

public void setYear(int y) {year = y;}

public int getDay() {return day;}

public int getMonth() {return month; }

public int getYear() {return year; }

public void display() {System.out.println(day + " - " + month + " - " + year);}
}
/*执行结果:
date=9
7 - 7 - 1970
22 - 1 - 2000
*/


接着掌握这段相对复杂的程序内存分析

package com.buaa.day3;
import static java.lang.System.*;
/*程序解读:
* Circle c1 = new Circle(new Point(1.0,2.0), 2.0);
* 首先执行Circle c1 ,c1是一个引用类型的变量,所以给它分配一块栈内存存放一个Circle对象的引用(也就是地址),
* 接着new Point(1.0,2.0)在堆内存里分配Point对象,
* 接着  Circle(Point p, double r) {//把圆心定到原点上。局部变量P指向Point对象,
o = p; //让Circle对象的成员变量o指向指向Point对象的堆内存
radius = r;

* 接着new Circle(new Point(1.0,2.0), 2.0);在堆内存分配Circle对象,并且让Circle对象的成员变量O指向point对象,
* 这行代码的顺序之所以是这样是因为“=”的优先级比“new”的优先级低。
*
* 执行结果:c1指向Circle对象的堆内存,Circle对象的成员变量O指向了point对象的堆内存
*
* *****************************************************************
*
* Circle c2 = new Circle(5.0);
* 内存里又分配一块Circle对象,c2指向此对象
*     Circle(double r) {
o = new Point(0.0, 0.0);c2指向的Circle对象的成员变量O指向了point对象的堆内存,内容为0.0, 0.0
radius = r;
}
*
* *****************************************************************
*
* c1.getO().getX()
* c1.getO()
* public Point getO() { return o;//分配一块临时内存区域,此区域的值和O里的值一样,指向了Point对象的堆内存,内容为1.0,2.0

}
*  c1.getO().getX()返回1.0
*
*
*
*
* */
public class TestCircle {
public static void main(String args[]) {

Circle c1 = new Circle(new Point(1.0,2.0), 2.0);
Circle c2 = new Circle(5.0);
out.println("c1:("+c1.getO().getX()+","+c1.getO().getY()+"),"+c1.getRadius());//执行完之后main方法栈内存只剩下c1,c2
out.println("c2:("+c2.getO().getX()+","+c2.getO().getY()+"),"+c2.getRadius());
out.println("c1 area = "+c1.area());
out.println("c1 area = "+c2.area());
c1.setO(5,6);
c2.setRadius(9.0);
out.println("c1:("+c1.getO().getX()+"," +c1.getO().getY()+"),"+c1.getRadius());
out.println("c2:("+c2.getO().getX()+","+c2.getO().getY()+"),"+c2.getRadius());
out.println("c1 area = "+c1.area());
out.println("c1 area = "+c2.area());
//验证一个点是否在一个圆之内
Point p1 = new Point(5.2, 6.3);
out.println(c1.contains(p1));
out.println(c1.contains(new Point(10.0,9.0)));

}
}

class Point {
private double x;
private double y;
Point(double x1, double y1) {
x = x1;
y = y1;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double i) { x = i; }
public void setY(double i) { y = i; }
}

class Circle {
private Point o;
private double radius;
Circle(Point p, double r) {//把圆心定到原点上
o = p;
radius = r;
}
Circle(double r) {
o = new Point(0.0, 0.0);
radius = r;
}

boolean contains(Point p) {//计算一个点是否在一个圆中
double x = p.getX() - o.getX();
double y = p.getY() - o.getY();
if(x*x + y*y > radius * radius) return false;
else return true;
}

public void setO(double x, double y) {
o.setX(x);
o.setY(y);
}
public Point getO() { return o;//分配一块临时内存区域,此区域的值和O里的值一样,指向了Point对象的堆内存

}
public double getRadius() { return radius;}
public void setRadius(double r) { radius = r;}
public double area() {
return 3.14 * radius * radius;
}
}
/*执行结果:
c1:(1.0,2.0),2.0
c2:(0.0,0.0),5.0
c1 area = 12.56
c1 area = 78.5
c1:(5.0,6.0),2.0
c2:(0.0,0.0),9.0
c1 area = 12.56
c1 area = 254.34
true
false

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