JVM运行数据区加载.class文件及new一个对象的过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28666081/article/details/85346470
以下我们将会结合JVM运行时数据区+(加载、验证、准备、解析、初始化、使用、卸载) 来讲解加载过程,此过程不涉及到JVM运行时数据区外的内存空间。更多相关内存请看后续文章。

1 先概述下JVM运行时数据区:
 
 

2 再说说[加载、验证、准备、解析、初始化、使用、卸载]七个阶段:
2.1 jvm加载.class过程:
1 加载(使用类加载器-详情见我其他博客的双亲委派模式/当前类加载器/线程上下文类加载器):
- 1.1 通过类全限定名获取该类二进制字节流
- 1.2 将字节流转为方法区的运行时数据结构
- 1.3 在方法区生成对应Class对象(存在Class文件信息中),作为该类的各种数据入口
2 验证:验证.class文件是否符合jvm要求,如魔数开头、版本、字节码、符号引用等(这些均在编译期已生成)
3 准备:初始化类变量(如static int i; => 初始化为0),放到运行时常量池里,如果定义如下则直接赋好值"5"如下例子:
- private static final i = 5; 运行时常量池直接给i赋值5。
- 3.1 将字符串对象的实例引用值存到String Pool。 
4 解析:将常量池中的符号引用转为直接引用(该阶段也可以是初始化后,如动态绑定),期间会与String Pool作比较
5 初始化:执行到了<clinit>阶段,初始化静态变量赋值,然后初始化静态代码块。会先初始化当前类的parent,及最先赋值java.lang.Object的类变量(如果有的话)
 
 
2.2 jvm new一个实例的情况如下:
1 new一个实例,如new People();
2 到Class文件信息的常量池中检查是否有People这个类的符号引用,没有就执行类加载过程。
3 为People对象去堆分配内存(分配的大小已在类加载过程中确定),默认分到Eden区,进行一次GC后没被回收才转移到Survivor区。
- 两种分配方式:指针碰撞(堆规整,直接内存整移一份当前对象实例大小即可)、空闲列表(堆不规整,用列表记录那些内存可用)
- 注意点:带有压缩功能的垃圾收集器(如Serial、ParNew)才使java堆规整。
- 为实例分配内存空间时,通过CAS同步、本地线程缓存这两种确保线程安全性
- 内存分配完后,将分配到的内存空间都为零,不包含对象头(什么是对象头?详情看另一篇文章:《Synchronized关键字解析》),此时字段都为0/0L....。
4 执行<init>方法,把对象按程序员意愿初始化,如private int i = 1;此时就真的把1赋给 i。
 
 

参考文章:
《深入理解java虚拟机》
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/qq_28666081/article/details/85346470
今日推荐