[Java] 开课吧--JVM

向上委托,向下加载

收到加载任务后,先交给父类加载器,只有当父类加载器无法完成,才会执行加载

保证只有一个类加载器加载,避免重复加载

破坏:JDK 1.2后才使用,JDK  1.1的核心类没有通过双亲委派定义

[Java] 开课吧--JVM

[Java] 开课吧--JVM

如何判断两个Class对象是否相同

class字节码相同

classLoader相同

JVM运行数据区按线程使用情况分类

线程独享区域

虚拟机栈、本地方法栈、程序计数器

不需要垃圾回收

线程共享区域

堆和方法区

垃圾回收、类的静态数据和对象

[Java] 开课吧--JVM

HotSpot

JDK 1.6:字符串常量池在永久代

JDK 1.7:依然有永久代,但字符串常量池在堆中

JDK 1.8:不存在永久代

字符串常量池

节省内存空间,所有类共享一个字符串常量池

如何存数据

对象存储

快速搜索:StringTable(hashtable)

StringTableSize:决定搜索效率

[Java] 开课吧--JVM

JVM中最大的一块内存

GC最重要区域

堆的内存分配通过垃圾收集器实现

JVM启动时实现

存什么

JDK 1.6:对象、数组

JDK 1.7+:对象、数组、字符串常量池、静态变量 

参数

-Xms:初始大小,单位m,g

-Xmx:最大大小

-XMn:新生代(年轻代)

-XX:SurvivorRatio=8:年轻代中Eden与Servivor比例,默认为8:1

-XX:PermSize:非堆内存初始大小,一般默认200m

-XX:MaxPermSize:菲堆最大大小

-XX:NewSize(-Xns):年轻代内存初始大小

-XX:MaxNewSize(-Xmn):年轻代最大大小   

[Java] 开课吧--JVM

 

[Java] 开课吧--JVM

分配原则

优先在Eden分配,如果Eden不足,进行一次MinorGC

大对象直接进入老年代(超过Eden一半)

长期存活对象进入老年代(15次GC未被回收)

年轻代没有空间存放的对象进入老年代

分配方式

指针碰撞:内存地址连续(年轻代)

空闲列表:内存地址不连续(老年代)

分配安全

虚拟机给A线程分配内存过程中,指针未修改,B线程可能同时使用了同一块内存

CAS(乐观锁):不加锁,假设没有冲突,如果冲突就重试,直到成功

TLAB(本地线程分配缓冲):每个线程预先分配一块内存

分配担保

当在新生代中无法分配内存时,把新生代对象转移到老年代,然后把新对象放入腾空的新生代

对象内存布局

对象头:锁信息、对象年龄、类型指针

实例数据:成员变量

对齐填充

程序计数器

当前线程执行下一个字节码的行号

用于线程切换后,能恢复到正确执行的位置

Java虚拟机栈

基于栈和基于寄存器

基于栈(操作数栈):一个程序调用需要10个基于栈的指令,JVM一次编译,到处运行

基于寄存器:同样的一个程序调用只需要两三个基于寄存器的调用,和操作系统有关

栈帧

支持虚拟机进行方法执行的数据结构

存储方法的局部变量表、操作数栈、动态链接、方法返回地址

局部变量表--冰箱;操作栈--盘子

方法调用时创建

操作数栈的每个元素可以是任意Java数据类型,32位数据类型占一个栈容量

每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,可在类加载阶段或第一次使用时转换为直接引用(静态解析),或每次运行时转换为直接引用(动态连接)

静态解析:直接引用,即对应方法的内存地址

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydgwp.html