jvm之管理内存
- 程序计数器:当前线程所执行的字节码的行号指示器。程序计数器是唯一一个不会出现
OutOfMemoryError
的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。 - Java虚拟机栈 方法调用 一个方法调用都会有对应的栈帧被压入栈中 局部变量表:各种数据类型、对象引用类型 操作数栈:用于存放方法执行过程中产生的中间计算结果。另外,计算过程中产生的临时变量也会放在操作数栈中。 栈的内存不允许动态链接,栈会出现StackOverFlowError,当可以动态扩展,但是在扩展的时候没有办法申请到足够的内存空间,则抛出
OutOfMemoryError
异常。Java 方法有两种返回方式,一种是 return 语句正常返回,一种是抛出异常。不管哪种返回方式,都会导致栈帧被弹出。也就是说, 栈帧随着方法调用而创建,随着方法结束而销毁。无论方法正常完成还是异常完成都算作方法结束。 - Java本地方法栈:本地方法栈则为虚拟机使用到的 Native 方法服务。
-
堆 大部分情况,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 S0 或者 S1,并且对象的年龄还会加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中。这里最容易出现
OutOfMemoryError 当jvm花太多时间执行垃圾回收比关切只能回收很少的堆空间的时候,就会报这个错误
-
元空间是永久代的实现 把永久代换成元空间的原因——整个永久代有一个 JVM 本身设置的固定大小上限,无法进行调整(也就是受到 JVM 内存的限制),而元空间使用的是本地内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。
-
运行时常量池:常量池表会在类加载后存放到方法区的运行时常量池中。
-
字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
-
直接内存:直接内存是一种特殊的内存缓冲区,并不在 Java 堆或方法区中分配的,而是通过 JNI 的方式在本地内存上分配的。
-
对象的创建——类加载检查、分配内存(指针碰撞、空闲列表,分配方式由Java堆是否规整决定 而 Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。)——初始化零值——设置对象头(这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。)——执行init方法
- 对象在内存中的布局可以分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。对齐填充起到占位作用,8字节的整数倍
- 对象的访问
- 内存分配以及回收原则
- 优先在Eden区分配,当内存不够的时候会触发Minor GC,Survivor空间内存足够的情况下转入,并将对象年龄设为 1(Eden 区->Survivor 区后对象的初始年龄变为 1)。不足的情况下通过 分配担保机制 把新生代的对象提前转移到老年代中去
- 大对象直接进老年代
- 长期存活的对象将进入老年代,对象在 Survivor 中每熬过一次 MinorGC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中。
-
Java之垃圾回收
- 死亡对象判断方法
- 引用计数法 有地方引用就加1,引用失效减一。 问题:循环引用
- 可达性分析算法 GC Roots
- 引用类型总结:
- 强引用:不会回收,内存不足,抛出OutOfMemoryError 错误,
- 软引用:可有可无,内存不足会回收,与引用队列联合使用
- 弱引用:一旦发现,不管内存是否足够,都会回收。但是垃圾回收器是一个优先级很低的线程,因此不一定会很快发现。与引用队列联合使用
- 虚引用:任何时候都可能被回收。主要用来跟踪对象被垃圾回收的活动。
- 如何判断一个常量是废弃常量?运行时常量池主要回收的是废弃的常量
- 如何判断一个类是无用的类? (1)该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。(2)加载该类的
ClassLoader
已经被回收。(3)该类对应的java.lang.Class
对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
- 垃圾收集算法
- 标记清除算法:创建对象,标记o;然后可达对象标记为1 ,扫描阶段清除为o的 。内存碎片
- 复制算法: 内存缩小为原来的一半
- 标记-整理算法:老年代,标记之后不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后清理掉端边界以外的内存
- 分代收集算法:根据对象存活周期的不同将内存分为几块,采用不同的收集算法
- 垃圾收集器
- serial收集器:暂停其他所有的工作线程,只用一条垃圾收集线程完成垃圾收集工作。
新生代采用标记-复制算法,老年代采用标记-整理算法。 简单高效
-
parNew收集器:只是使用多线程区进行垃圾收集
-
parallel scavenge收集器 关注吞吐量 以及cpu资源的场合
-
CMS收集器 是一种以获取最短回收停顿时间为目标的收集器。第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
-
G1收集器 一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region