浅谈java程序运行时内存分配及运行机制

                                                                            浅谈 java程序运行时内存分配及运行机制 

 

第一部分:内存分配

一、 基本概念

   1.每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,

   2.每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆,该进程的所有线程共享这个堆

   3.jvm为每一个线程分配一个栈,单个线程独享栈。

   4.Java中分配堆内存是自动初始化的,引用存放于栈中,对象存放于堆中,引用包含着指向堆区的指针

   5.当变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收。


二.java内存分区

         l  栈:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。

         l  堆:用来存放对象及对象中的非静态的成员变量,对象所属类中的方法不在堆中。

         |  方法区(静态区):

           方法区存储内容有:

           1.类的类型信息

               1.1 此类型的完整有效名 
               1.2 此类型直接父类的完整有效名(除非这个类型是interface或是 java.lang.Object,两种情况下都没有父类) 
               1.3 此类型的修饰符(public,abstract, final的某个子集) 
               1.4 此类型直接接口的一个有序列表

            2.类型的常量池( constant pool):jvm为每个已加载的类型都维护一个常量池。常量池就是这个类型用到的常量的一个有序集合,包括实际的常量(string, integer, 和             floating point常量)和对类型,域和方法的符号引用。池中的数据项象数组项一样,是通过索引访问的。 

      因为常量池存储了一个类型所使用到的所有类型,域和方法的符号引用,所以它在java程序的动态链接中起了核心的作用 

           3.域信息 :jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序, 
              3.1 域名   3.2 域类型   3.3 域修饰符(public, private, protected,static,final volatile, transient的某个子集)

           4.方法信息 
              jvm必须保存所有方法的以下信息: 
              4.1方法名 
              4.2 方法的返回类型(或 void) 
              4.3 方法参数的数量和类型(有序的) 
              4.4 方法的修饰符(public, private, protected, static, final, synchronized, native, abstract的一个子集)除了abstract和native方法外,其他方法还有保存方法的字节码(通过        解析字节码调用方法)操作数栈和方法栈帧的局部变量区的大小

            5.异常表

            6.类变量:及静态变量


三:小结:

     1.类的静态变量属于类,存在方法区。类的成员变量属于对象,存于堆。方法中的局部变量存于栈。

     2.静态方法属于类,非静态方法属于对象。

     3.对象是类的一个实例,类是对象的抽象集合。因此对象可以使用类方法和类变量,对象层面的方法(非静态方法)也可以使用类成员变量,

   与之相反的是:类无法使用非静态成员变量和非静态方法,类层面的方法(静态方法)也无法使用非静态类型的成员变量。

 

第二部分:运行过程分析

 类的加载时机:

  1)当new创建一个对象时。
  2)使用java.lang.reflect包的方法对类进行反射调用的时候
  3)当加载一个类的时候,如果发现其父类还没有进行过加载,则需要先触发其父类的加载。
  4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的),虚拟机会优先加载这个主类。
  5)当使用类的静态成员:如  StaticCode.num = 9;  StaticCode.getNum();
 其中(1)属于对象方式的类加载    (2)(4)(5)属于类方式的类加载
  

  类加载过程:

   java程序经过编译后形成*.class文件,内含JVM的字节码。通过类加载器将字节码(*.class)加载入JVM的内存中。类加载过程主要涉及JVM的方法区。JVM将类加载过程分成加载,连接,初始化三个阶段,其中连接阶段又细分为验证,准备,解析三个阶段。通常把加载和初始化简化成为一个过程,因为加载就会引起初始化。

  

 需要初始化的部分:

   1)静态成员变量

   2)非静态成员变量

   3)静态代码块:用于给类初始化,类加载时就会被加载执行,只执行一次。

   4)非静态代码块:用于给对象初始化,只要建立对象该部分都会执行,优先于构造函数执行,每个对象只执行一次。

构造函数:给对象的对象初始化,建立对象是,选择相应的构造函数初始化对象

   5)构造器

 

   类的部分加载机制:

  a.当通过类方式(类加载时机部分的(2)(4)(5))进行类的加载时:仅会加载静态成员变量,静态代码块
   

  b.当通过对象方式(类加载时机部分的(1))进行类的加载时:所有需要初始化的部分均要初始化

     对象方式加载类的初始化顺序:

     1.父类静态成员和静态初始化快,按在代码中出现的顺序依次初始。
     2.子类静态成员和静态初始化块,按在代码中出现的顺序依次初始。
     3. 父类的实例成员和实例初始化块,按在代码中出现的顺序依次初始。
     4.初始父类的构造方法。
     5.子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
     6.初始子类的构造方法。

    通过test类解释上述知识:

public class test {
	int t;
    static{
    	int i=6;
    	System.out.println(i);
    }
    {   int f=9;
    	System.out.println(f);
    }
    public test() {
		// TODO Auto-generated constructor stub
    	t=8;
    	System.out.println(t);
	}
	
    public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("test");
		new test();
	
	}

}


1.出现mian方法,开始用类方式加载这个类,并加载到方法区,因为时类方式所以仅会初始static块,此时打印6

2.初始化完毕,继续执行main方法,执行System.out语句(也加载了system类)打印test

3.继续执行main方法,出现new test();进行对象方式的类加载,并加载到方法区,这次加载会初始化普通块,打印9,然后初始构造器,打印8.初始完成,将对象存入堆中。

4.mian执行结束,程序结束





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值