JVM内存

2021/03/03

JVM

1.什么是JVM

JVM是可运行java的虚拟机,包括

1.字节码指令集
2.寄存器
3.栈
4.垃圾回收
5.堆
6.存储方法域

2.JVM运行时

1.java文件->编译器->字节码文件(.java->.class)
2.字节码文件->JVM->机器码

3.JVM内存区域

JVM的内存主要分三块:线程私有区、线程共享区、直接内存区

  线程私有区:程序计数器、虚拟机栈、本地方法区
  线程共享区:JAVA堆、方法区
  直接内存区: 直接内存    

生命周期:

  线程私有区:私有区生命周期与线程相同,依赖用户线程启动而创建,结束而销毁。
  线程共享区:随虚拟机的启动/关闭而创建/销毁。 
  直接内存: 不属于JVM运行时内存,用于NIO中的零拷贝。    

程序计数器

当前线程所执行的字节码的行号指示器,多线程执行时每条线程都有独立的程序计数器

计数器记录的是虚拟机字节码指令的地址。如果是native方法则为空。
唯一没有OutOfMemoryError的区域。

虚拟机栈

每个方法执行时都会创建一个栈帧,用于存储(局部变量表、操作数栈、动态链接、方法出口) 一个方法从调用到完 成,对应着一个栈帧在虚拟机中入栈到出栈的过程。

栈帧:用于存储数据和部分结果的数据结构,同时也被用来处理动态链接
     (Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)

本地方法区

与虚拟机栈类似,本地方法区为Native 方法服务。

JAVA堆

堆空间是java程序员最为了解的,存放对象的地方,可以通过 -Xmx 参数指定大小,一般区域分为: 对于大部分的垃圾回收器而言这三个区域也是逻辑上区分的,也有物理上个分开的。 堆是线程共享的一块内存区域,用于存储创建的对象和数组。也是GC回收的最重要的内存区域。

一.JAVA堆中对象的分配

  1. 指针碰撞(内存规整的情况下):
  2. 空闲列表(内存不规整的情况下):
  3. 本地线程分配缓冲: 每个线程预分配内存缓冲区

二.JAVA堆中的对象布局

1.对象头

  • 存储对象运行时数据(Mard Word):
    • 哈希码
    • GC分代年龄
    • 锁状态标志
    • 线程持有的锁
    • 偏向锁id
    • 偏向时间戳
  • 类型指针: 指向类元数据的指针,若是数组则多一块用于记录数组长度

2.实例数据

成员变量的字段内容

3.对齐填充

保证对象是8个字节的整倍数

新生代(Eden 区/Survivor区 8:1:1):
    占用堆的1/3,用于存放新生的对象。
    Eden:
        Java新对象的出生地(注:若新对象占用内存过大,直接分配到老年代),内存不够时触发GC。
    Servivor:
        上次GC的幸存者。
老年代:
    占用堆的2/3,存放生命周期长的内存对象。老年代不会频繁的GC,当新生代进入老年代,
    导致内存不够时或没有足够大的连续内存空间,才会发生GC。


GC复制算法:
    1. 把 Eden和 ServivorFrom存活的对象复制到 ServicorTo,把对象的年龄+1.
        (注: 如果年龄代到老年代标准,则迁移到老年代) (ServicorTo内存不够直接放入老年代)
    2. 清空 eden 、 servicorFrom
    3. ServicorTo 和 ServicorFrom 互换

GC标记清除算法:
    1. 扫描所有老年代,标记出存活的对象。
    2. 回收没有标记的对象。
    
GC ROOT:
	1.虚拟机栈中引用的对象
	2.方法区中类静态属性引用的对象
	3.方法区中常量引用的对象
	4.本地方法栈中引用的对象

方法区(永久代)

用于存储JVM加载的类信息、常量、静态变量、即时编译器编译后的代码,不会GC。

运行时常量池:方法区的一部分,用于存放编译期生成的各种字面量和符合引用


java8(元数据):
    JAVA8中移除了永久代,取而代之的是元数据区。区别在于元数据区不在虚拟机中,而是直接使用
    本地内存,类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中。这样可以
    加载多少类的元数据就不再由MaxPermSize 控制, 而由系统的实际可用空间来控制。

能摸鱼就很舒服

Show Disqus Comments
扫码关注公众号:纯洁的微笑
发送 290992
即可立即永久解锁本站全部文章