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堆中对象的分配
- 指针碰撞(内存规整的情况下):
- 空闲列表(内存不规整的情况下):
- 本地线程分配缓冲: 每个线程预分配内存缓冲区
二.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
即可立即永久解锁本站全部文章