zoukankan      html  css  js  c++  java
  • JVM笔记

    准备工作 :java对象的创建过程(内存分析),首先准备如下Pet对象,这个类中默认有一个无参构造器,并在main函数中调用Pet中的无参构造方法,生产了一个Pet对象,此时,这个对象的属性是没有值的,然后我们分别给它的name和age进行了赋值,并调用了它的shout()方法,这是从表面可以看到的,那么它在内存当中是如何执行的?

    首先,我们要知道,程序一运行,它需要加载一些程序要运行的模板,所以第一步,它肯定会把我们Application,这个类的一些代码信息放到我们的内存中来,比如它首先加载Application这个类到方法区中,那这个类里面有个方法叫做main方法,然后它还有一些字符串,我们把它一般叫做常量,然后它里面其实一般有个常量池的,来专门存放一些常量,然后这个常量里面,现在有个什么东西,叫 旺财 这样一个东西,当然,还有一个age=3,这个3就不是常量了,是一个int类型的数字,OK,这是咱们的main方法,然后,走到这个地方,加载完Application类,然后现在要执行运行一下,是不是要执行main方法,我们说了, 这个main方法都在哪里面,那main方法是在栈里面的最底下,然后因为栈里面的所有东西结束的时候,那main方法一开始执行在最底下,当main方法结束,它便弹出去的时候,栈结束了,其实这个程序,差不多也就结束了。

    然后,说一下main方法执行的时候,它走到了第一步,那我们在Pet dog = new Pet();,这里打一个断点,边看debuger,边来调试;那么它第一步首先new了一个Pet,它就走到Pet这个类中来,所以它一旦new的话,它肯定要去加载Pet这个类,加上Pet类之前并没有加载过,那现在肯定会把Pet这个类,也加载到方法区中:

    那这个宠物类Pet现在就加载进来了,加载进来,这个宠物类,它有一些它自己的一些属性,什么name,age,shout方法,3个东西;那现在就把这Pet类也加载进来,Pet类里也有个常量池,它的常量池里面,也有一些字符串,但是我们这个shout方法中的字符串,是输出的,叫了一声,其实它并不算常量池里的,所以先把常量池这个地方先简单的忽略掉,以便于理解,那现在这个Pet类就有了,就相当于我们在 Application类中,new Pet的时候, 它就进入了Pet这个类,进入了Pet这个类,那我们看下它里面的值,当前name属性等于null,age等于0,所以说,我们这个时候,加载到方法区中的Pet类中的属性,它是肯定没有值的,因为它都是默认值,String类型默认等于null,int类型默认等于0,那现在对象的模板加载进方法区里来了,加载进来之后,main方法里是不是要为Pet这个类,生成一个具体对象,通过方法区中的这个Pet类的模板,生成一个Dog对象,所以说,当等于dog的时候,又在栈中又生成了一个变量,比如说就叫dog,那这个dog是放在栈里面的,然后栈里面,它真正new出来的东西,它在堆里面会生成;

     那dog是在栈里面的,它只是一个变量名字,是一个引用,或者叫变量名;然后真正的对象在哪个位置呢,是在咱们堆里面的,通过方法区中的这个Pet模板,去new了一个Pet,比如堆里这个地方的Pet,我们给它简单写个内存地址,叫0x0001,假设是这个,然后我们栈中的dog变量,是不是就引用到了这个0x0001,堆中的这个地址,那现在我们栈中的dog,就指向了堆中的Pet,它有个地址叫0x0001,然后现在的话,默认的name是不是等于null,age=0,然后它还有自己的一个方法,这个方法叫做shout(),它这个方法其实new的时候,它去调用了方法区中,Pet模板里的shout()方法,它是这样一个关系,有了这个shout,它是不是会"叫了一声",那它就有一些基本的操作,那它这个模板就差不多了。

     然后咱们第一个线,就走完了,就new Pet(),这一步就走完了,它其实进了无参构造的时候,它就做了这个事情。 

    那做完之后,我们现在main方法中,做一件事情,把dog.name,是不是等于旺财啊,相当于给这个name要赋值了,赋值了方法区里的Application类中,这个常量池里的旺财,它先做了一个这样的事情,它把这个方法区中常量池中旺财,丢给了这堆中的这个name,于是乎这个name才有了值啊,是这么一个过程。

    然后堆中的这个name, 现在 这个地方就叫做旺财,ok,那这个旺财有了,age是不是等于3,然后,它把3也赋值给堆中的这个age,ok,那age也有值了,那么shout()方法,堆里面的这个new出的Pet,它是调用了我们下面方法区里面Pet当中的shout()方法,因为方法区里的Pet的shout() 和,堆中new pet里的shout,这两个方法是一样的,它并没有传递任何的参数,那这样的话,我们现在走到这一步,在main方法中调用shout()方法这一步,那所有的值就都赋完了呀!

    所有的值赋完了,那么这个对象,它就有这些值,它在堆中就有这些值了,然后我们就可以去使用这个堆中new出的Pet了,使用它的时候,它就存在这个旺财跟age=3了。

    那我们再来做一件事情,我们现在new了一个dog,那我们再来new一个,比如说new了一个猫cat,Pet cat = new Pet();,那我们现在有只小猫了,对不对,那这个猫cat,它怎么在内存里面存在呢,其实,它是在栈里面,又加了一个引用变量名,叫cat,引用变量名,那它就是个引用,它引用的,是要指向真实的,那cat,它是不是等于new Pet(),所有它又去堆中new了一个Pet, 那它new这个Pet的时候,比如它是0x0002,这是堆中的第二个对象了吧,它的name默认new的时候,又是null,age=0,那这样的话,第二个对象是不是就有了,那cat就指向了,这第二个Pet对象,这两个dog和cat所指向的堆中的对象,就是完全不一样的对象了。为什么,我们说类是一个模板new出来的对象,就在栈中,这个栈中的对象,它就是一个引用名,要是给cat所指向的堆中的Pet对象,那么猫就有自己的名字了,它就是这么一步一步来做的。 

     

     那在引用变量,它本身在栈里,就是个引用变量名,它真正指向的是堆中的具体的对象,只是我们通过栈,给它起了一个名字,相当于本质上它们还是一样的东西,那面向对象的 封装继承多态,也可能让同一个变量名,或者同一个类型,它也可能有不同的一些状态。然后,这个方法区的最后,我还留了一个静态方法区,那被static声明的东西, 它就是在这个地方的,我们所有带static的关键字的,一进来就加载在这个地方,所以说它是一开始就加载的,和类一起加载,所以说,如果如果想为了方便大家去调用的,我们都会用static修饰,也就是放在这个静态方法区,因为类一加载,它就加载了,那么类一加载,这个静态方法区里的东西就加载了,那它会有一个什么样的效应呢,是不是所有对象,在堆中的对象,都可以去用到这个静态方法区里的东西,就是无论是哪个对象,都是可以直接调用静态方法区中的东西,而无需去new出一个新的实例。

     那另外需要说明的是,这个关于堆,栈,以及方法区,其实堆和方法区是一个整体,我们左侧的叫做栈,然后右边的一系列都是堆,然后堆里面有个特殊的区域,叫做方法区, 这个方法也是属于堆的。

     堆一般是存放我们具体创建出来的对象,而栈里面,都是一些方法,加一些变量的引用,那现在我们就可以知道,为什么我们同时new的都是Pet,但是会产生不一样对象,因为它是存在于堆中不同区域,就是它的地址可能不同,然后它在栈中的引用变量名也不同,所以造成了这种都是new的Pet对象,确实两个不同的对象。

      

  • 相关阅读:
    pgspider sqlite mysql docker 镜像
    pgspider docker 镜像
    pgspider基于pg 的高性能数据可视化sql 集群引擎
    diesel rust orm 框架试用
    golang 条件编译
    Performance Profiling Zeebe
    bazel 学习一 简单java 项目运行
    一个好用node http keeplive agnet
    gox 简单灵活的golang 跨平台编译工具
    mailhog 作为smtp server mock工具
  • 原文地址:https://www.cnblogs.com/HarryVan/p/14444552.html
Copyright © 2011-2022 走看看