zoukankan      html  css  js  c++  java
  • java内存

    java虚拟机内存结构

    • 程序计数器
      程序计数器属于线程私有,存储下一条待执行的指令的地址,实现跳转、循环、分支等功能,程序计数器不存在内存溢出OOM的问题。

    • 虚拟机栈
      虚拟机栈属于线程私有,线程每执行一个方法时都创建一个栈帧,栈帧包含了该方法的局部变量表(包括八大基本数据类型的变量、对象引用)、操作数栈、动态链接、方法出口等信息,每一个方法的执行对应栈帧的入栈和出栈过程。线程如果请求的栈深度大于虚拟机所允许的最大深度,抛出StackOverflowError异常。虚拟机栈动态扩展过程中,如果超过规范的大小,抛出OutofMemoryError异常。

    • 本地方法栈
      本地方法栈属于线程私有,虚拟机栈为执行的java方法服务,本地方法栈为Native方法服务。同虚拟机栈,也可能会抛出SOE和OOM异常。(Native方法???查找)

    • 方法区
      方法区是各个线程共享的内存区域。方法区主要存放类的信息,常量,静态变量。内存不够时,抛出OOM异常。


    • java堆主要存放对象实例和数组。Java堆是垃圾收集器管理的主要区域,在垃圾回收中,将堆划分为新生代、老年代,还可以划分出每个线程私有的分配缓冲区。Java堆物理上不连续,逻辑上连续。内存不够分配内存时,抛出OOM异常。

    • 运行时常量池
      class文件包含类的版本、字段、方法、接口等信息外,还包括常量池信息,指类中的字面量和符号引用。在类加载时常量池存放在java内存中的运行时常量池中。

    对象创建过程(hotspot虚拟机)

    类加载->内存分配->初始化为0->配置对象->执行init方法

    1. 类加载
      首先检查类是否被加载过,如果没有,必须先执行相应的类加载过程。
    2. 内存分配
      对象所需内存的大小在类加载完成之后便已经确定。内存分配有两种实现方式:
      • 指针碰撞。假设java堆内存是绝对规整的,可以使用的内存在一边,已经使用的在另一边,中间存放着指针作为分界点的指示器,内存分配就是将指针向空闲的内存移动对象大小相等的距离,
      • 空闲列表。java堆中内存可用和空闲的内存是交替的,空闲列表记录堆中哪些内存块是可用的,当需要分配内存时,从空闲列表中找到一块合适的空间分配给对象。
    3. 初始化为0
      内存分配之后,虚拟机将分配到的内存都初始化为零值,这一操作保证了对象实例字段在java代码中可以不赋初始值就可以直接食用,程序能访问到这些字段的数据类型所对应的零值。
    4. 配置对象
      对对象进行必要的设置,包括这个对象属于哪个类,如何找到这个类的元数据信息,对象的哈希码,对象的GC分代年龄等信息,这些信息存放在对象的对象头中。
    5. 方法
      执行init方法,把对象按照开发者的意愿进行初始化。

    对象的内存布局

    对象在内存中存储的信息包括对象头,实例数据,对象填充。

    • 对象头
      存储对象运行所需要的数据,如哈希码,GC分代年龄、锁状态标志等。另一部分是类型指针,对象通过类型指针找到所属于的类。
    • 实例数据
      对象存储的有效信息,程序代码中所定义的字段内容。
    • 堆起填充
      起占位符作用。对象的起始地址必须是8的整数倍。

    对象的访问定位

    • 句柄访问
      堆中存放着某个对象的句柄池,引用则存放句柄池的地址。句柄池中包含指向对象的地址以及指向对象所属类的地址。
    • 指针访问
      引用直接存放对象的地址,
  • 相关阅读:
    [背包问题][二进制优化] Jzoj P4224 食物
    [并查集][排序] Jzoj P4223 旅游
    [哈夫曼树][优先队列] Bzoj P4198 荷马史诗
    [hash][差分][虚树] Jzoj P6011 天天爱跑步
    [dp] Jzoj P6012 荷马史诗
    [dp][递归] Jzoj P4211 送你一棵圣诞树
    [数学] Jzoj P3912 超氧化钾
    堆学习笔记(未完待续)(洛谷p1090合并果子)
    [AC自动机]luogu P2444 病毒
    [概率期望][DP]luogu P3830 随机树
  • 原文地址:https://www.cnblogs.com/a1225234/p/11068385.html
Copyright © 2011-2022 走看看