简单的java代码在内存加载过程(详解)

内存

(1) 寄存器(Registers)。这是速度最快的存储场所,因为寄存器其他所有存储媒介都不同:它位于处理器内部。不过,寄存器的数量十分有限,所以寄存器是根据需要由编译器适当地分配。作为一个程序员,我们对此没有直接的控制权,也没办法在程序里头感觉到寄存器的任何存在迹象。

(2) Stack(栈)。位于一般的RAM(random-access memory,随机访问内存)中。处理器通过其指针(“栈指针”,stack pointer)获得处理的直接支持。栈指针若向下(后)移,会分配新的内存;若向上(前)移,则会释放那些内存。这是一种特别快、特别有效率的数据存储方式,速度仅次于寄存器。由于Java编译器有责任产生“将stack指针前后移动”的程序代码,所以它必须能够完全掌握它所编译的程序中“存在stack里头的所有数据的实际大小和存活时间”。如此一来便会限制程序的弹性。由于这个限制,尽管有些Java数据要存储在栈里——特别是对象句柄,但Java对象并不放到其中。

(3) Heap(堆)。Heap是一种通用性质的内存存储空间(也存在于RAM中),用来置放所有Java对象。“内存堆”或“堆”(Heap)胜过stack之处在于,编译器不需知道究竟得从堆里分配多少存储空间,也不需知道从堆上分配的空间究竟要存活多长的时间。因此,用堆存储数据时会得到更大的灵活性。要求创建一个对象时,只需用new即可。执行这些代码时,会在堆里分配空间。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会比从栈里分配花掉更长的时间(假设你真的可以在Java中像C++一样地从stack上产生对象的话)!

(4) 静态存储空间(Static storage)。这儿的“静态”(Static)是指“位于固定位置”(也在RAM里头)。静态存储空间存放着“程序运行期间”一直存在的数据。可用static关键字将某个对象内的特定成员设为静态,但Java对象本身永远都不会置入静态存储空间。

(5) 常量存储空间(Constant storage)。常量值通常被直接置于程序代码里头。因为它们永远都不会改变,所以也是安全的。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(read-only memory,ROM)中。

(6) 非RAM存储空间(Non-RAM storage)。若数据完全存活于程序之外,则程序不运行时数据仍继续存在,脱离了程序的控制范围。

* 本节我们将重点看2,3,4*

new Classname的加载到内存方式

class Car{
String color;
String number;
public void run(){
System.out.println(color+”:”+number);
}
public void method(){
int x=0;
}
}
class CarDemo{
public static void main(String[] args){
//测试:Car类中的run方法
//1.创建Car的对象,给对象起个名字。
Car c = new Car();
//c是类型的变量。C指向了一个具体的Car类型的对象
c.color=”red”;
c.number=4;
//2.通过已有的对象调用该对象的功能。
c.run();
}
}

在内存加载的过程
1. 在栈中加载主方法(main)
2. 然后执行到new Car();在堆中创建一片连续的地址,并在栈中的Main方法会有Car C这个变量。而堆中的这片地址会有成员变量。例如:头地址0x22
3. Car c = new Car();所以将该地址值赋给了C = 0x22,而C是引用变量(此处省略部分)
4. c.color=”red”,c.number=4;则c指向的地址0x22, 然后逗号作用和C语言一样
5. 运行到c.run(),然后将该方法压栈(略略略).

方法体进栈的过程

请参考以上代码Car类里method()方法

Car c = new Car();
c.method();

若运行到第二个语句时,将在内存进行这样操作

  • 将Method()方法压进栈,同时创建了int类型的X变量。
  • 当方法执行完时,将弹栈。

变量的加载到内存的方式

变量的域范围有两种,一种是成员变量,另外一种则是局部变量。
成员变量也称之为类属性,所以在堆中创建对象的时候,对象中就已经包含了成员变量了。
而局部变量 是在方法体里,或者能说是在代码块里
成员变量和局部变量的区别:

  1. 区别一:定义的位置不痛。
    成员变量定义在类中
    局部变量定义在方法中以及语句里。
  2. **区别二:内存位置不同
    成员变量存储在堆内存中对象中。
    局部变量存储在栈内存中方法中。
  3. 区别三:生命周期不同。
    成员变量随着对象的出现而出现,随着对象的消失而消失。
    局部变量随着方法运行而出现,当方法运行完弹栈而消失。
  4. 区别四:初始化不同。
    成员变量因为在堆内存中,所以有默认初始化值(有关构造方法)。
    局部变量没有默认初始化值,必须初始化后才可以使用。

调用构造器的加载到内存方式

class Person{
private String name;
private int age;
Person(String n ){
name = n;
}
public void speak(){
System.out.println(“name=”+name+”,age=”+age);
}
}
class PersionDemo2{
public static void main(String[] args){
Person p = new Person(“lisi”);
p.speak();
}
}
1. main 方法 进栈
2. 读到Person p = new Person(“lisi”);
new 的时候开辟了一个空间,
开始创建成员变量 name 、age ,然后取他们的默认值
String name = null int age = 0 ;
然后才调取他们的构造函数(该方法进栈),因为这里是Person(String n )
所以构造函数只初始化name。

This 原理

讲到这里,大家肯定有疑问,为什么方法进栈会知道自己是哪个对象调用的方法呢,毕竟一个类有千万个实例化后的对象。
原因就是方法在入栈的时候不止是创建局部变量还会创建一个this来装被哪个对象调用的对象地址。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值