zoukankan      html  css  js  c++  java
  • 深入理解java虚拟机(1)------内存区域与内存溢出

    在C++领域,关于C++的内存存储,结构等等,有一本书:深度探索C++对象模型,讲解的非常透彻。

    而Java确把这一工作交给了虚拟机来处理。

    我们首先来看看关于内存的问题。

    1.问题:

    1)java 的局部变量存在那里,类型怎么存放的?

    2)static 变量

    3)final 变量

    4)method是存放的那里的

    5)class类 & 内部类 是如何存放

    2.java虚拟机运行时数据区

    2.1程序计数器

    线程隔离数据,记录当前线程执行的位置。

    PC计数器

    由于Java虚拟机的多线程,是由线程轮换的方式分配CPU的。所以线程切换后,需要恢复到原来执行的地方

    所有线程都需要一块内存来记录这个执行位置,此内存是线程私有的。这块内存称为Program Counter Registers

    2.2Java虚拟机栈

    这个栈就是我们常见的java 面试题中一般会问 heap & stack 的区别。 这里的stack就是我们说的虚拟机栈。

    这个栈是存放每个method执行的时候的局部变量表,动态连接,方法出口等信息。这个栈也是线程私有的。每个方法执行过程,对应

    一个栈帧在虚拟机栈的入栈和出栈过程。

    局部变量表存放:已知基本类型的变量,对象引用,也就是指向对象的指针,或者句柄,和retuanaddress地址。

    栈中可以理解为存放对象的引用,而对象本身存放在堆。

    当然64位的double & long会占据2个Slot。其余的数据占据1个。

    如果申请的内存不够,就会OOM。

    2.3本地方法栈

    这个东西同Java虚拟机栈非常类似,这里存放这native方法的一些信息。

    2.4Java堆

    千呼万唤始出来,对象实例就是存放在这个地方。也是java内存最大的地方。

    java所有的线程共享这一块内存。此内存的唯一目的就是存放对象实例。

    GC的主要工作就是释放这里不用的内存。

    这块区域为所有线程共享。所以android就会有activity或者service在非前台状态下,是否低优先级的情况。

    2.5方法区

    这块地方存放的就是已经加载的类信息,静态变量,常量等。

    String abc = “abc”; 这后面的“abc”就存放在这里。

    2.5.2 运行时常量区

    java在非编译阶段,也可以是一种常量的形式,比如:

    String str = "abc"+"d";

    它会生成“abcd”常量在运行时候。

     运行是常量是方法区的一部分。

    3.HotStot虚拟机对象探秘

    java对象的创建过程分成2步:

    1)加载类信息,存放在方法区

    2)根据类信息,分配内存存放对象,内存在堆区。

    分配内存的常见方式:

    1)假设内存在堆区分为2块,一块是已经在使用的,一块是还没有分配的,这样我只要设置一个指针,来区分这两块区域。

    当分配新的内存时,移动指针即可。

    2)内存区域是不连续的,这样我只能在空闲的内存中,找到一块足够大的内存来分配,这种为空闲列表的方式。

    但是,当分配内存时,会有同步的问题。

    要么保证分配操作是原子操作,或者就是给每个线程优先分配一小块内存(Thread Local Allocation Buffer)

    这个东西在android looper机制的时候,有所体现。

    接下来就是对对象进行设置:

    对象是那个类的实例,如何才找到对象的元数据信息,对象的hash表,对象的GC分布年龄等。

    从程序员的角度看,一个对象在内存中已经创建,但是init的方法还没有执行。对象还没有按照程序员的意愿进行初始化。

    3.1 对象的内存布局

    在HotStot中,对象的布局可以分为3块:对象头,实例数据,和对其填充。

    对象头根据虚拟机的位数,32bit或者64bit。

    这部分被以极限的算法,来存储不少的信息。

    实例数据部分,存的是真正有效的信息,这部分会存父类的信息和子类的信息。

    3.2对象的访问方式

    reference 指向的是另一个类的对象,所以它指向的实际是堆中的另一块内存而已。

    HotSopt使用的是第二种方式。

    5.几个问题的答案

    1)java 的局部变量存在那里,类型怎么存放的?

    java的局部变量存放在虚拟机栈中的 该线程的栈帧,里面的局部变量表里面。

    class对象的引用存放在局部变量表里。对象实例存放在java堆中。对象类型或者类信息存放在方法区。

    2)static 变量

    也存放在方法区内。

    3)final 变量

    final只是修饰变量的赋值行为,对变量的内存没有影响。所以有没有final不影响变量的存放位置。

    4)method是存放的那里的

    方法的内容 也就是code,所有的method都在class类中,或者是类信息,所以存放在方法区内。

    5)class类 & 内部类 是如何存放

    一个普通的类 & 内部类本质上是一样的,所以就是1)问题中描述的情况。

    对象引用句柄或指针,存放在每个线程的局部变量表内。

    对象实例存放在java堆中,

    对象类加载信息存放在方法区中。

    6)一个类的成员属性,它的内存是那块?

    类的成员属性,某种意义上和C++/C 里面的全局变量类似。但是JVM其实没有全局变量这样一个概念。

    成员属性的对应的内存可以肯定是在堆中,可以肯定成员变量的基本信息是在类信息中的。所以成员属性

    的相关内存都在java堆中。

    参考:

    《深入理解Java虚拟机》  周志明

  • 相关阅读:
    UVA657 The die is cast(DFS、BFS)
    三分
    【洛谷P6105】iepsmCmq
    【CF613D】Kingdom and its Cities
    【洛谷P4294】游览计划
    【洛谷P3500】TESIntelligence Test
    【洛谷P6189】[NOI Online 入门组] 跑步
    【洛谷P2973】Driving Out the Piggies
    【洛谷P3164】和谐矩阵
    【洛谷P4161】游戏
  • 原文地址:https://www.cnblogs.com/deman/p/4826748.html
Copyright © 2011-2022 走看看