类的加载和内存分配的过程

类的加载和内存分配的过程

1.类的加载过程

在java应用程序开发中,只有被java虚拟机装载的Class类型才能在程序中使用。只要生成的字节码符合java虚拟机的指令集和文件格式,就可以在JVM上运行

  1. class文件加载

    1. 将编译好的.java程序,通过java编译器生成.class文件,然后由类加载机制加载到jvm中,存储在方法区中。
    2. 并且会随之生成一个相应的Class对象,这个对象一般也是存放于方法区中的,他包含了有关类的信息(版本,字段,方法…),一般也会存放在方法区中。
  2. 装载

    • 验证:验证字节码文件是否符合规范。
    • 准备:对静态域分配内存并进行默认初始化。(方法区中进行分配)
    • 解析:虚拟机常量池内的符号引用替换为直接引用的过程。(比如String s =“hello”,转化为 s的地址指向“aaa”的地址)
  3. 初始化

    为静态域执行初始化,如果该类有父类,就先对其父类进行初始化。实际过程中如果没有对该字段进行引用则不用进行初始化。

2.jvm内存分配

jvm的内存主要分为三部分:方法区。其实每个部分还包括分区。

我们知道java是多线程的,其中方法区线程共享的。线程私有数据区

public class test{
    static int i=1;
    final q=5;
    String s="hello";
    float f=2.0f;
    public void f(){
        int a=10;
    }
    public static void ff(){}
    public static void main(String args[]){
        test t=new test();
        t.f();
        String ss=new String("hello");
    }
}

拿上面的java程序举例:

  1. 首先test.class文件被类加载器加载到jvm,存放在方法区中,class文件中除了存放类的信息,字段、方法等描述信息之外,还有个常量池:包含了在编译期生成的字面量(量本身-也就是值)和符号引用(在解析过程变成直接引用)这部分的内容在类加载进入方法区的常量池中存放

    由此我们可以知道反射的基础

    在装载类的时候,加入方法区中的所有信息,最后都会形成Class类的实例,代表这个被装载的类。方法区中的所有的信息,都是可以通过这个Class类对象反射得到。我们知道对象是类的实例,类是相同结构的对象的一种抽象。同类的各个对象之间,其实是拥有相同的结构(属性),拥有相同的功能(方法),各个对象的区别只在于属性值的不同。同样的,我们所有的类,其实都是Class类的实例,他们都拥有相同的结构-----Field数组、Method数组。而各个类中的属性都是Field属性的一个具体属性值,方法都是Method属性的一个具体属性值。

  2. 经过一系列过程(验证-准备-解析-初始化)找到程序入口main()方法

  3. main()方法进栈,创建一个test引用变量,并为其分配空间。对引用变量进行初始化,指向的是堆内存中实例的地址。当对象在堆内存中创建出来后成员变量也随之被存储在对象中。

  4. f()方法进栈,为局部变量a分配空间,进行初始化,f()出栈,释放局部变量a所占的栈空间,销毁。

  5. 创建字符串引用常量,分配内存空间,初始化值,指向堆内存中的对象地址,堆内存对象指的是常量池中的字符串常量hello的地址。

成员变量:定义再类中,作用于全类,存在于堆内存中的对象中的,随着对象的消亡而消亡,所以不管是基本类型还是引用类型都是在堆内存的对象中的。这里的s在堆内存中存放的是常量池中hello的地址值。

**局部变量:**定义在方法中,随着方法的进栈相应的会为该局部变量开辟栈空间,随着方法的出栈而销毁,此时的引用类型变量在栈空间存储的是对象的地址,所指向的对象是存放于堆内存中的。

常量:字符串常量和基本类型常量都是存放在方法区中的常量池的。

总结

  1. 栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。
  2. 以上的栈、堆、代码段、数据段等等都是相对于应用程序而言的。每一个应用程序都对应唯一的一个JVM实例,每一个JVM实例都有自己的内存区域,互不影响。并且这些内存区域是所有线程共享的。这里提到的栈和堆都是整体上的概念,这些堆栈还可以细分。
  3. 类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。

这3篇关于内存分配和类加载讲的很详细

https://www.cnblogs.com/langtianya/p/4441206.html

https://blog.csdn.net/m0_37499059/article/details/80451799

http://www.cnblogs.com/dqrcsc/p/4671879.html

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值