0
点赞
收藏
分享

微信扫一扫

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


JVM运行时数据区+(加载、验证、准备、解析、初始化、使用、卸载)



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



 



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

 



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的类变量(如果有的话)



 



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

 



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。



 



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

 



举报

相关推荐

0 条评论