zoukankan      html  css  js  c++  java
  • JVM

    自动内存管理

    运行时数据区

    线程私有的:虚拟机栈、本地方法栈、程序计数器
    线程共享的:方法区、堆

    程序计数器

    线程私有的区域,指向本线程下一条要执行的字节码。不会抛出OOM异常

    虚拟机栈

    为执行java方法提供服务,如果栈深度超过允许范围,会抛出StackOverflowError;如果允许虚拟机栈扩展,在申请不到内存无法进行扩展时,会抛出OutOfMemoryError

    本地方法栈

    为执行native方法提供服务,类似于虚拟机栈,也会抛出StackOverflowError和OutOfMemoryError

    对象实例和数组分配内存要在堆上进行。会抛出OOM异常。
    堆可以位于物理上不连续的空间,逻辑连续即可。
    GC的主要区域

    方法区

    保存虚拟机运行过程中加载的类信息、常量、静态变量等。
    无法分配内存时,抛出OOM异常
    这个区域的GC只要回收无用常量、卸载类

    对象的创建过程

    类加载、分配内存(如何保证原子性?)、内存清零、设置对象头、init

    对象的内存布局:对象头、实例数据、对齐填充

    垃圾回收机制

    自动垃圾回收需要考虑的三个问题:

    • 回收哪些内存?对象存活判断(引用计数、可达性分析)
    • 什么时候回收?
    • 怎么回收?

    垃圾回收算法

    标记-清除

    空间碎片

    复制算法

    Eden:From Survivor:To Survivor=8:1:1
    复制操作效率低

    标记-整理

    分代算法

    新生代和老年代采用不同算法

    垃圾收集器

    CMS

    Concurrent Mark Sweep,顾名思义,采用标记清除算法回收垃圾,工作在老年代,多线程。工作过程如下:

    • 初始标记(Stop The World):标记与GC Roots直接相关的对象
    • 并发标记:根据上一阶段的标记遍历标记
    • 重新标记(STW):处理上一阶段用户线程对内存做的改动
    • 并发清除

    CMS的缺点:

    • 对CPU资源非常敏感
    • 浮动垃圾:并发清除阶段由用户线程产生的垃圾内存
    • 空间碎片:标记清除算法的缺陷

    G1

    Garbage-First,多线程,新生代和老年代不再物理隔离,将内存分区Region,新生代和老年代都由一系列的Region组成,维护Region的优先队列,每次优先回收价值大的Region(因此叫GarbageFirst),标记整理算法

    工作过程:

    • 初始标记:STW,标记与GC Roots直接相关的对象
    • 并发标记:遍历标记
    • 最终标记:STW,修正
    • 筛选回收:STW,对Region根据回收价值和成本进行排序,按照用户期望进行回收

    GC 分为两类:minorGC和major/fullGC。
    minorGC发生在新生代,快;
    fullGC发生在老年代,慢一个数量级

    内存分配策略

    自动内存管理可以分为两个模块:如何分配内存、如何回收内存

    堆的分区

    总体分为新生代和老年代
    新生代采用复制算法回收内存,因此又可以分为三个区:Eden、From Survivor、To Survivor

    jvm分配内存的常用策略

    下面来看jvm分配内存的常用策略:

    • 对象优先分配在Eden区
    • 大对象直接进入老年代,利用担保机制
    • 长期存活的对象进入老年代:每个对象都有年龄,如果对象熬过第一次minorGC并且进入了Survivor区,则age=1;以后每次存活,age++;当age达到一定值之后,对象晋升老年代

    新生代对象内存分配过程:首先查看eden区空间是否够用,不够用则进行一次minor gc到survivor区,如果survivor区也不够用,通过分配担保机制转移到老年代。

    JVM调优

    类加载

    类加载是如何把字节码转换成运行时数据

    类加载的过程

    类加载分为:
    加载、验证、准备、解析、初始化、卸载

    其中加载、验证、准备、初始化、卸载这5个过程必须按顺序开始(而不是“完成”)

    加载

    加载过程做了什么?

    • 根据类全限定名获取二进制字节码
    • 将字节码转换为运行时数据结构放在方法区
    • 创建该类对应的Class对象

    验证

    验证字节码是否符合虚拟机规范

    准备

    类变量分配内存、置零

    解析

    符号引用转化为直接引用
    符号引用:字面量
    直接引用:地址

    初始化

    类构造方法 <clinit>(),由类变量赋值语句和static块合成

    类加载器

    类和它的类加载器共同确立了这个类在jvm中的唯一性

    双亲委派模型

    类加载器具有层次化,从上往下依次是:

    • 启动类加载器
    • 扩展类加载器
    • 应用类加载器

    双亲委派模型的工作过程:
    如果一个类加载器收到了一个类加载请求,它首先会把加载任务交给上一层类加载器,如果上层类加载器不能完成类加载,则由自己完成类加载。

    破坏双亲委派模型

    • 重写loadClass()方法
    • 线程上下文类加载器 Thread Context ClassLoader
    • OSGi

    并发

  • 相关阅读:
    封装
    面向对象的思想
    Arrays工具类
    二分查找
    选择排序
    冒泡排序
    对象数组
    二维数组
    一维数组
    循环语句注意事项
  • 原文地址:https://www.cnblogs.com/darknessplus/p/10431448.html
Copyright © 2011-2022 走看看