JVM基础知识详解

1.JVM内存模型

蓝色为进程共享,黄色为线程共享

-Xms 为jvm启动时分配的内存,比如-Xms200m,表示分配200M

-Xmx 为jvm运行过程中分配的最大内存,比如-Xms500m,表示jvm进程最多只能够占用500M内存 

-Xss 为jvm启动的每个线程分配的内存大小,默认JDK1.4中是256K,JDK1.5+中是1M

 

程序计数器

较小的内存空间,当前线程的所执行的字节码的行号指示器,通过此来选取下一条所需要的执行的字节码指令,分支、循环、跳转、异常处理、线程恢复都需要依赖计数器。线程切换时需要保存PC计数器的状态。

虚拟机栈

虚拟机栈描述了java方法执行的内存模型,指的是java内存中的栈内存,内部含有局部变量表。

每个方法执行的时候都会创建栈帧,用于存储局部变量表(存放局部变量、对象引用)、操作数据栈(运算数据)、动态链接、方法出口等信息

异常:

StackOverflow Error,虚拟机栈内存不允许动态扩展大小,当线程请求栈内存达到虚拟机栈的最大深度(递归层次太深),则跑出该异常

OutOfMemory Error,线程请求栈内存用完了,无法动态扩展了,则抛出该异常

本地方法栈

为native方法创建的栈区,调用非java方法(例如C/C++)时使用

方法区

存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代码数据

运行时常量池

是方法区的一部分,用于存储常量等信息,主要分为

字面量:文本字符串,final常量,基本数据类型的值(1,true等)

符号引用:类和结构的完全限定名(类名、枚举名),字段名和描述符,方法名和描述符

2.堆-内存模型

参数

 -Xms

 初始堆大小。如:-Xms256m

 -Xmx

 最大堆大小。如:-Xmx512m

 -Xmn

 新生代大小。通常为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。实际可用空间为 = Eden + 1 个 Survivor,即 90%  

 -Xss

 JDK1.5+ 每个线程堆栈大小为 1M,一般来说如果栈不是很深的话, 1M 是绝对够用了的。

 -XX:NewRatio

 新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3

 -XX:SurvivorRatio

 新生代中 Eden 与 Survivor 的比值。默认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10  

 -XX:PermSize

 永久代(方法区)的初始大小

 -XX:MaxPermSize

 永久代(方法区)的最大值

 -XX:+PrintGCDetails

 打印 GC 信息

 -XX:+HeapDumpOnOutOfMemoryError

 让虚拟机在发生内存溢出时 Dump 出当前的内存堆转储快照,以便分析用

java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域存放对象实例与数组等( new出来的)

堆被分为新生代(Young)、老年代(Old)、永久代(Perm,jdk8之后被移除,由元空间metaspace替代,元空间使用的是物理内存)

 

young:old默认为1:2。可通过-XX:NewRatio指定young的大小。-XX:PretenureSizeThreshild参数指定老年代大小,默认为0代表不管多大先在eden中分配内存。

Eden:from:to = 8:1:1

几乎所有的对象都是在eden中产生的,Eden区域为连续内存空间分配极快,对象的生命周期很短,当eden区满的时候,会将存活对象会在from和to中来回复制,过程为eden+from->to,下一次则为eden+to->from,会保证有一个Survivor为空,复制一次年龄加1,当年龄到达阈值后转移到Old中

老年代存储的是一些大对象和需要年需存储内存空间的对象(静态变量、缓存、线程池等)

回收过程

  • 绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,因此在其上分配内存极快;

  • 最初一次,当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);

  • 下次Eden区满了,再执行一次Minor GC,将消亡的对象清理掉,将存活的对象复制到Survivor1中,然后清空Eden区;

  • 将Survivor0中消亡的对象清理掉,将其中可以晋级的对象晋级到Old区,将存活的对象也复制到Survivor1区,然后清空Survivor0区;

  • 当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代,但这只是个最大值,并不代表一定是这个值)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代。

3.垃圾回收机制

minor gc(Young gc)

在年轻代中存在的回收算法,当JVM无法为新对象分配内存(Eden区满)时会触发minor gc,此回收会造成所有应用线程停顿,但相对于Old区GC时间忽略不计

使用的是复制算法,其中一块内存用完就复制到另外一块上面,将已使用过的内存清理

Full GC

清理整个堆的GC事件,包括新生代、老年代、元空间,CMS并发收集就是这个模式

采用的是标记-清除算法,位置不连续,容易产生碎片

收集器

新生代收集器:Serial、ParNew、Parallel Scavenge

老年代收集器:CMS、Serial Old、Parallel Old

整堆收集器: G1

  • Serial收集器: 单线程的收集器,收集垃圾时,必须stop the world,使用复制算法。

  • ParNew收集器: Serial收集器的多线程版本,也需要stop the world,复制算法。

  • Parallel Scavenge收集器: 新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞吐量。如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%。

  • Serial Old收集器: 是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。

  • Parallel Old收集器: 是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法。

  • CMS(Concurrent Mark Sweep) 收集器: 是一种以获得最短回收停顿时间为目标的收集器,标记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎片。

  • G1收集器: 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选标记。不会产生空间碎片,可以精确地控制停顿。

CMS收集器和G1收集器的区别:

  • CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用;

  • G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;

  • CMS收集器以最小的停顿时间为目标的收集器;

  • G1收集器可预测垃圾回收的停顿时间

  • CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片

  • G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。

  • jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

GC日志

public static void main(String[] args) {
    Object obj = new Object();
    System.gc();
    System.out.println();
    obj = new Object();
    obj = new Object();
    System.gc();
    System.out.println();
}

 

 

4.java对象创建

 

类加载检查

执行new后,会检查该参数是否在常量池中有该类的符号引用(一般是有对应的构造函数),并检查该类是否已经被加载、解析和初始化过,如果没有就先执行类加载过程

 

分配内存

类加载完成后就可以确定所需内存大小,从Java堆中分配一块确定大小的内存。

分配方式

指针碰撞:内存规整的情况下,用一个指针指向已分配和未分配的分界点,通过移动指针来分配内存

空闲列表:内存不完整情况,分配内存互相交错,通过一张表记录空闲内存块信息

分配并发问题

创建对象时需要考虑线程安全,主要有两种方式

CAS+失败重试

CAS是乐观锁的一种实现方式,每次不加锁假设没有冲突去完成操作,失败就重试直到成功。虚拟机采用CAS保障更新操作的原子性

TLAB

每个线程预先在Eden分配一片区域(TLAB),线程分配时先在TLAB中分配,TLAB用完之后再使用CAS策略

初始化零值

初始化所有字段对应的零值

设置对象头

对象的hashCode,对象的GC分代年龄信息,锁标志状态等。另一部分是类型指针,指向类元数据的指针,确定对象是哪个类的数据

 

JVM知识精华汇总(转载)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值