1.每个java虚拟机实例(进程)运行一个java程序(线程).程序结束,虚拟机退出.
2.java虚拟机通过调用调用这样的一个方法来启动java程序:public static void main(String [] arg){};
3.java虚拟机实例的内部有两种线程:守护线程,非守护线程.守护线通常是虚拟机实例自己使用的,比如执行垃圾收集的线程.但是java程序也可以把自己创建的线程标记为守护线程.但是java中的初始线程(开始于main()的那个线程)是属于非守护线程.当程序中的所有非守护线程结束了,则虚拟机退出.
4.java虚拟机实例包括:类装载器子系统,运行时数据区(方法区,堆,栈,程序计数器,本地方法栈),执行引擎.
A:类装载子系统:装载类,提取类的相关信息,将其数据放到运行时数据区的相应部位.其过程包括:装载:查找并装载类的二进制数据----连接:验证(确保导入的类型是正确的).准备(属性分配内存,并初始化为默认值).解析(把类型中的符号应用转化为直接引用.)-----初始化:把类属性初始化为正确的初始值.
B:方法区:虚拟机实例中所有的线程共享.存储类解析后的一切信息.
细化为:
a:常量池:虚拟机实例为每个类型创建一个常量池.存放直接常量("sd",3,3.45,'a'),用final修饰的
b:静态存储区:存储static修饰的
c:一般属性信息:名称 类型 修饰符
d:方法信息:名称 返回类型 参数数量和类型 修饰符,如果不是抽象方法还有保存:方法的字节码,操作数栈,栈帧中局部变量的大小,异常表.
C:堆:虚拟机实例中所有的线程共享.存储java程序中的所有对象(new出来的)
D:栈:每个线程都要自己的栈.每个线程被创建时分配自己的栈,其中存储方法的参数 局部变量,运算的中间结果,返回值.java的栈是由很多的栈帧组成的,每个帧都保存着一个方法的调用状态.
E:程序计数器:每个线程都要自己的程序计数器.每个线程被创建是分配一个程序计数器,总是指向下一条要执行的指令.
F:本地方法栈:每个线程中都要自己的本地方法栈.
代码实例:
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;
}
省略get,set方法………
}
public class Test{
public static void main(String args[]){
int date = 9;
Test test = new Test();
test.change(date);
BirthDate d1= new BirthDate(7,7,1970);
}
public void change1(int i){
i = 1234;
}
对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:
1. main方法开始执行:int date = 9;
date局部变量,基础类型,引用和值都存在栈中。
2. Test test = new Test();
test为对象引用,存在栈中,对象(new Test())存在堆中。
3. test.change(date);
i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。
4. BirthDate d1= new BirthDate(7,7,1970);
d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。
5.main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收