• Java面向对象内存分析


    title: Java面向对象内存分析
    date: 2018-07-28 11:12:50
    tags: JavaSE
    categories: 
    - Java
    - JavaSE
    

    一、Java虚拟机的内存区域

    Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area

    具体如图所示:

    1.栈Stack

    栈的特点:

    1. 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量操作数方法入口等)

    2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数,局部变量等)

    3. 栈属于线程私有,不能实现线程间的共享!

    4. 栈的存储特性是 “先进后出,后进先出”

    5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间

    2.堆Heap

    堆的特点:

    1. 堆用于存储创建好的对象和数组(数组也是对象

    2. JVM只有一个堆,被所有线程共享

    3. 堆是一个不连续的内存空间,分配灵活,速度慢

    如图:

    3.方法区

    方法区的特点:

    1. JVM只有一个方法区,被所有线程共享

    2. 方法区实际也是堆,只是用与存储类、常量相关的信息!

    3. 用来存放程序中永远是不变或唯一的内容。

      (类信息【Class对象】、静态常量、字符串常量等)

    二、程序执行的内存变化过程

    2.1 一个对象的创建分为四部

    1. 分配对象空间,并将对象成员变量初始化为0或为空

    2. 执行属性值的显示初始化

    3. 执行构造方法

    4. 返回对象的地址给相关变量

    2.2 程序执行过程

    1.方法区加载类的信息

    类的代码信息,静待方法,静态常量被加载到方法区之中

    2.调用main方法(程序执行的入口)

    在栈中开辟一个栈帧,调用main方法

    初始stu=null

    下一步执行构造方法

    开辟第二个栈帧,调用构造器,开始执行该方法

    构造器根据方法区里面的模板信息开始在堆区新建一个对象。方法结束后在堆区新建对象成功

    3.构造器执行结束

    构造器执行结束,对象属性为初始状态

    构造器方法的栈帧回收删除

    stu指向新生成的stu对象

    4.main方法继续执行

    继续执行mian方法,为stu的属性进行赋值等, 例如使得部分属性指向字符串常量,最终方法执行结束

    代码如下:

      package top.dlkkill.oo;

    public class Student {
    public String id;
    public String name;
    public Student() {
    System.out.println("Create a Student");
    }
    public static void live() {

    }
    public void study() {

    }
    public static void main(String[] args) {
    Student stu=new Student();
    stu.name="abc";
    stu.id="111";
    }
    }

    三、多态内存分析

    内存图如图所示:

    这里要注意:

    • super指向的是父类

    • 无论是哪里的this,指向的都是新构造出来的Cat对象,比如在Aniaml里面有一个方法test();

      方法中通过this.voice()调用了voice方法,如果新构造的是一个Cat对象,那么这个调用的voice方法就是调用的Cat里面重写的voice方法,而不是Animal方法!这一点比较重要,在Servlet中,我们继承一个Servlet,并重写doGet方法就可以实现我们想要的功能就是基于这个原理,例如父类中有service()方法,方法调用了doGet,我们重写了doGet方法,这里就会调用我们重写的方法

    代码如下:

      package top.dlkkill.oo;

    public class AnimalTest {

    public static void testAnimalVoice(Animal c) {
    c.voice();
    if(c instanceof Cat) {
    ((Cat) c).catchMouse();
    }
    }

    public static void main(String[] args) {
    // TODO Auto-generated method stub
    Animal a=new Cat();
    Cat a2=(Cat) a;
    testAnimalVoice(a);
    }

    }
    class Animal{
    String str;
    public void voice() {
    System.out.println("普通动物叫声");
    }
    }
    class Cat extends Animal{
    public void voice() {
    System.out.println("喵喵喵");
    }
    public void catchMouse() {
    System.out.println("抓老鼠");
    }
    }

    程序执行,首先便会代码信息,类的信息以及静态方法、常量等加载到方法区之中。然后第一句执行,构造了一个Cat对象,具体如图所示,然后将地址交给变量使得变量指向该Cat对象。之后及时将地址交给一个Animal变量,但本质上指向的依然是一个Cat对象而不是变成Animal对象。

  • 相关阅读:
    Linux常用性能检测命令
    Linux环境下获取网卡连接状态
    posix多线程有感线程高级编程(均衡负载CPU绑定)
    posix多线程有感线程高级编程(线程调度以及优先级设置)
    posix多线程有感线程高级编程(线程和fork,exec)
    posix多线程有感线程高级编程(进程的优先级)
    linux多线程和锁
    posix多线程有感—sysconf系统变量
    posix多线程有感线程高级编程(线程堆栈)
    Linux基本网络设置(IP配置等,网卡驱动缓存,网卡中断)
  • 原文地址:https://www.cnblogs.com/DLKKILL/p/9387683.html
Copyright © 2020-2023  润新知