JVM 内存分布

  • 线程共享数据区:
    方法区->类信息,静态变量
    堆->数组对象
  • 线程隔离区
    虚拟机栈-> 方法
    本地方法栈->本地方法库 native
  • 堆、程序计数器
  • JVM 运行数据

程序计数器

线程隔离 ,比较小的内存空间,当前线程所执行的字节码的行号
线程是一个独立的执行单元,由 CPU执行
唯一没有 OOM 的地方,由虚拟机维护,所以不会出现 OOM

虚拟机栈

执行的是Java方法

方法的调用就是栈帧入虚拟机栈的过程
栈帧:局部变量表(变量) 、操作数栈(存放a+b的结果 )、 动态链接(对对象引用的地址),方法出口(return的值)
线程请求的栈深度大于虚拟机所允许的深度StackOverflowError

本地方法栈

执行的是 native 方法的一块 java内存区域,一样有 栈帧
hotspot将 Java 虚拟机栈和本地方法栈合二为一
jvm标准是 java 虚拟机栈和本地方法栈分开

java内存中存放对象实例的区域,几乎所有的对象实例都在这里分配
所有线程共享
新生代、老年代
jmap -heap pid;

方法区

各个线程共享的内存区域
存储已被虚拟机加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据
Hotspot用永久代实现方法区(让垃圾回收器可以管理方法区),对常量池的回收和卸载
方法区会抛出 OOM,当他无法满足内存分配需求时

运行时常量池

运行时常量池是方法区的一部分,Class 中除了字段、方法、接口的 常量池,存放编译器生成的字面量和符号引用,这部分内容由类加载后进入方法区的运行时常量池中存放。

StringTable是HashSet结构
方法区的一部分,受到方法区的限制,依然会 OOM

Java 对象创建过程


-> static方法 static代码块

  1. new 指令,判断在常量池中有没符号引用,有则已被加载过
  2. 判断类是否被加载、解析、初始化
  3. 为新生对象在java堆里分配内存空间
    1) 指针碰撞(内存比较整齐)

    步骤:1. 分配内存 2. 移动指针,非原子步骤可能出现并发问题,Java虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性
    2)空闲列表(内存比较乱)
    存储堆内存空闲地址
    步骤:1.分配内存 2. 修改空闲列表地址 非原子步骤可能出现并发问题,Java虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性
  4. 将分配到内存空间都初始化零值
  5. 设置对象头相关信息 (GC分代年龄、对象的HashCode、元数据信息)
  6. 执行方法

    Java 对象内存布局

    对象属性的值->实例数据
    对象头 64 位机器存 64 位,32 位机器存 32 位,8 的倍数

Java 对象的访问

  1. 直接指针访问
  2. 句柄访问

    对比:
  3. 访问效率:直接指针访问效率高(hotspot采用这种方式)
  4. 垃圾回收:句柄访问效率高,垃圾回收只用更新句柄池,而直接指针访问方式则要更新 reference地址

垃圾回收算法

  1. 引用计数器

    当对象实例分配给一个变量时,该变量计数设置为 1,当任何其他变量被赋值为这个对象的引用的时,计数+1 (a =b,则b的引用对象实例计数器+1),当一个对象实例的某个引用超过了生命周期(方法执行完)或者被设置为一个新值,则该对象的实例引用计数器 -1
    无法解决循环引用
    可达性分析
    GC Root (虚拟机栈中的引用的对象、本地方法栈中引用的对象、方法区静态属性引用的对象、方法区常量引用的对象)

  2. 标记-清除

    标记需要回收的对象,在标记完成后统一回收
    不足:
    1.效率问题,标记清除 2 个过程效率都不高
    2.空间问题,标记清除后产生大量不连续的内存碎片,碎片过多当程序需要分配较大的对象时,无法找到足够的连续内存而不得不提前触发一次垃圾回收动作

  3. 标记-复制

    内存块 A存活的对象复制到内存块 B (Survivor to)里,然后将内存块A (Eden + Survivor from)清空,
    只有少部分对象移动,更多的对象是要被回收的
    Eden:Survivor from:Survivor to=8:1:1
    98%对象“朝生夕亡”,新生代可用内存容量 90%(80%+10%),98%的对象可回收是一般情况,当小于 90%的对象被回收的时候(10%以上的对象存活时),则 Survivor to 空间不够,则需要依赖老年代进行分配担保

  4. 标记-整理

    老年代不适合复制算法
  5. 复制操作增多 2. 额外 50%空间浪费 3. 经常需要额外的空间分配担保 4.可能老年代中对象 100% 存活

步骤:

  1. 标记
  2. 整理 将存活的对象移动到一端(左上方),从不规整变成规整,然后直接清理掉边界以外的内存

Serial 收集器


单线程垃圾回收器,用户线程到安全点先暂定,然后 GC 线程单线程串行进行,等 GC 线程回收完,然后用户线程再继续
特点:Stop the world
场景:桌面应用 (gc时间短)
用于新生代,client 端

ParNew 收集器

Serial收集器的多线程版本

用于新生代,唯一能和CMS 收集器配合工作,运行在 server 模式下
-XX:ParallelGCThreads 限制垃圾收集器线程数 = CPU 核数(过多会导致上下文切换消耗)
并行:多条垃圾收集线程并行工作,用户线程仍然处于等待状态
并发:用户线程与垃圾收集器同时执行,用户线程和垃圾线程在不同 CPU 上执行

Parallel Scavenge 收集器

新生代收集器,复制算法,并行的多线程收集器
关注吞吐量优先的收集器(吞吐量 = CPU 运行用户代码执行时间/CPU 执行总时间 ,比如: 99%时间执行用户线程,1%时间回收垃圾,这时吞吐量为 99%)高吞吐量可以高效率利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多的交互任务
CMS 关注缩短垃圾回收停顿时间,适合与用户交互的程序,良好的响应速度能提升用户体验
-XX:MaxGCPauseMillis 参数 GC 停顿时间,参数过小会频繁 GC
-XX:GCTimeRatio 参数,默认 99%(用户线程时间占 CPU 总时间的 99%)

Serial Old 收集器

是Serial 收集器的老年代版本
单线程老年代收集器,采用“标记-整理”算法

Parallel Old 收集器

是 Parallel Scavenge收集器的老年代版本
多线程老年代收集器,采用“标记-整理”算法

CMS 收集器

获取最短回收停顿时间为目标的收集器,采用“标记-清除”算法,用于互联网、B/S 系统重视响应的系统

步骤:

  1. 初始标记(不和用户线程一起运行,耗时短)—— 标记一下 GC Roots 能直接关联到的对象,速度很快
  2. 并发标记(和用户线程一起运行,耗时长) —— 并发标记阶段就是进行 GC RootsTracing,寻找 GC 引用链
  3. 重新标记(不和用户线程一起运行,耗时短)—— 为了修正并发标记期间因用户线程导致标记产生变动的标记记录
  4. 并发清除(和用户线程一起运行,耗时长)—— 扫描整个内存区域

缺点 :

  1. 对 CPU 资源非常敏感(并发标记阶段时间长,占用用户线程 CPU 时间)
  2. 无法处理浮动垃圾(程序在进行并发清除时,用户线程所产生的新垃圾)
  3. 标记-清除产生空间碎片

G1 收集器

面向服务端应用的垃圾收集器

Region->Remembered Set (解决 循环引用 )
检查 Reference (程序对reference类型写操作,检查 reference 引用类型)
步骤:

  1. 初始标记 —— 标记 GC Roots 能直接关联到的对象
  2. 并发标记 —— 从 GC Root 开始对堆中对象进行可达性分析,找出存活对象 ,这一阶段耗时较长,但可与用户程序并发执行
  3. 最终标记(Remembered Set Logs->Remembered Set)—— 修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程 Remembered Set Logs里面,最终标记阶段需要把 Remembered Set Logs的数据合并到 Remembered Set中
  4. 筛选回收(Live Data Counting and Evacuation)—— 只需要扫描 Remembered Set
    优势:
  5. 基于“标记-整理” 为主和 Region 之间采用复制算法实现
  6. 可预测停顿,降低停顿时间,但G1 除了追求低停顿外,还能建立可预测的停顿时间模型
  7. G1 直接对 Java 堆中的 Region 进行回收(新生代、老年代不再物理隔离,他们都是一部分 Region)
  8. 可预测的停顿时间模型,G1 跟踪各个 Regions 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region

堆内存分配

Java 堆分布图

对象分配的规则:

  1. 对象主要分配在新生代的 Eden 区 ( Eden区,From 区存活对象复制到 To区,Eden区,From区被回收,然后 To区对象拷贝到From区,再进行下一次垃圾回收 )
  2. 如果启动了本地线程分配缓冲,将按线程优先在 TLAB 上分配
  3. 少数情况下也可能直接分配到老年代 (放不下From和To区的都直接放到老年代)

大对象分配

大对象是指需要大量连续内存空间的 Java 对象,最典型的大对象是是那种很长的字符串以及数组
-XX:PretenureSizeThreshold 设置大于该值的对象直接分配在老年代,避免在 Eden 区以及 2 个Survivior区之间发生大量的内存复制

逃逸分析和栈上分配

逃逸分析:分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,称为方法逃逸。甚至还有可能被外部线程访问到,比如赋值给类变量或其他线程中访问的实例变量,称为线程逃逸。
栈上分配:把方法中的变量和对象直接分配到栈上,方法执行完后自动销毁,不需要垃圾回收介入,从而提高系统性能
-XX:+DoEscapeAnalysis 开启逃逸分析(jdk1.8默认开启 )
-XX:-DoEscapeAnalysis 关闭逃逸分析

命令

  1. ps -ef | grep java
  2. jps -m(启动参数) -l(类名) -v (JVM 参数)
  3. jstat -gc 27660 250 20 监视虚拟机各种运行状态信息
  4. jinfo 27660 查看和调整进程虚拟机(未被显示指定的)参数信息
  5. jmap 生成堆转储快照 -XX:+HeapDumpOnOutOfMemoryError
    jmap -heap 9366;
    jmap -histo 9366 | more; 显示堆中对象统计
    jmap -dump:format=b,file=/Users/mousycoder/Desktop/a.bin 9366 生成dump文件
    -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/mousycoder/Desktop/
    jhat /Users/mousycoder/Desktop/java_pid9783.hprof 图形分析Heap
    select s.toString() from java.lang.String s where (s.value != null && s.value.length > 1000 )
  6. jstack 线程快照(虚拟机内每一条线程正在执行的方法堆栈的集合,主要用于定位线程问题)
    shutdownHook 在关闭之前执行的任务
    jstack -l -F pid 强制输出

线程状态

  1. NEW
  2. RUNNABLE
  3. BLOCKED 一个正在阻塞等待一个监视器的线程处于这个状态(Entry Set)被动的阻塞
  4. WAITING 一个正在无限期等待另一个线程执行一个特别的动作的线程处于这一状态 (Wait Set)主动显式申请的阻塞
  5. TIMED_WAITING 一个正在限时等待另一个线程执行一个动作的线程处于这一状态
  6. TERMINATED 线程完成一个excution

JConsole

基于 JMX 的可视化监视、管理工具
开启 JMX 端口
nohup java -Xms800m -Xmx800m -Djava.rmi.server.hostname=192.168.1.250 -Dcom.sun.management.jmx
remote.port=1111 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar hc-charging-
server.jar &

互联网开发流程

Jconsole 内存分析思考过程

FullGC

Minor GC:当 Eden 区满,触发 Minor GC
FullGC:

  1. 调用System.gc() 建议虚拟机进行 Full GC,可通过 -XX:+DisableExplicitGC 来进制 RMI 调用System.gc()
  2. 老年代空间不足 大对象直接进入老年代,长期存活的对象进入老年代,当执行 Full GC后空间仍然不足,则抛出 OutOfMemoryError,为了避免上面原因引起 Full GC,调优时尽量做到让对象在 Minor GC 阶段被回收,让对象在新生代多存活一段时间以及不要创建过大的对象和数组
  3. 空间分配担保失败 使用复制算法的 Minor GC 需要老年代的内存空间作为担保,如果出现了 HandlePromotionFailure 担保失败,则会触发 Full GC
    建议:
  4. 减少-Xmx大小,缩短 GC 时间(堆内存设置越大,Full GC 时间越长,停顿时间也会越长)
  5. 集群部署

互联网问题

  1. 白名单问题
    解决方法:list.contain->set.contain->布隆过滤器(用户量大和用户量小系统解决方案不一样)
  2. 死锁
    解决方法:jstack 以及 new thread带上名称
  3. 堆内存泄露
    FullGC 出现正常频率为一天 1~2 次
    解决方案:jmap , heap dump on oom + jhat
  4. 堆外内存泄露
    heap堆使用率很低,但是有 OOM 以及 Full GC
    解决方法:btrace

学习秘籍

  1. 知识体系
  2. 面试前看下知识体系导图
  3. 坚持就胜利

【JVM 知识体系框架总结】的更多相关文章

  1. [转帖]【JVM 知识体系框架总结】

    [JVM 知识体系框架总结] https://www.cnblogs.com/mousycoder/p/11612448.html JVM 内存分布 线程共享数据区:方法区->类信息,静态变量堆 ...

  2. Python知识体系框架 思维导图

    技术文档已经独立整理! 请移步个人技术文档:https://anxiangchegu.github.io/technical-doc 如需更多Java.Python.大数据体系知识,请稳移步个人技术文 ...

  3. Java知识体系框架

    前言:自从出生,每个人都是一个学习者或探索者.永远保持一颗谦逊的心态,遵循一定的方法和规范,去学习和实践,永远记得走走停停,多回头看看自己走过的路,温故而知新,也能更好地指导未来的路怎么走(同样,本篇 ...

  4. jQuery基本知识体系图

    在w3school学习了jQuery,觉得看了一遍,代码敲了一遍,大概的知识点记住了,不过觉得还是把这些知识点,放到一张图上,形成自己的jQuery的知识体系.能做到,一看到jQuery,脑海就浮现j ...

  5. JVM核心知识体系(转http://www.cnblogs.com/wxdlut/p/10670871.html)

    1.问题 1.如何理解类文件结构布局? 2.如何应用类加载器的工作原理进行将应用辗转腾挪? 3.热部署与热替换有何区别,如何隔离类冲突? 4.JVM如何管理内存,有何内存淘汰机制? 5.JVM执行引擎 ...

  6. android项目架构 -----Android 知识体系与常用第三方框架

    好东西值得分享 ,这是网络上总结的一些开源的东西直接就拿过来了  .... Android通用流行框架大全 先把这张图放在这 ,先来谈一谈项目结构 .我喜欢将东西按模块来划分: 都知道module . ...

  7. 【转】Java开发必须要知道的知识体系

    Java Java是一门超高人气编程语言,拥有跨平台.面向对象.泛型编程等特性.在TIOBE编程语言排行榜中,连续夺得第一宝座,而且国内各大知名互联网公司,后端开发首选语言:非Java莫属.今天只是梳 ...

  8. from: Java开发必须要知道的知识体系

    from:  https://zhuanlan.zhihu.com/p/21895647 作者:靳洪飞链接:https://zhuanlan.zhihu.com/p/21895647来源:知乎著作权归 ...

  9. Java全栈工程师知识体系介绍

    Java全栈工程师,是指掌握多种技能,并能利用多种技能独立完成产品的人,也叫全端工程师(同时具备前端和后台能力),英文Full Stack developer. 那么想要成为一名合格的Java全栈工程 ...

随机推荐

  1. Dig命令使用大全(转自别人翻译),稍加整理

    Dig简介:   Dig是一个在类Unix命令行模式下查询DNS包括NS记录,A记录,MX记录等相关信息的工具.由于一直缺失Dig man page文档,本文就权当一个dig使用向导吧.   Dig的 ...

  2. Leetcode之深度优先搜索(DFS)专题-733. 图像渲染(Flood Fill)

    Leetcode之深度优先搜索(DFS)专题-733. 图像渲染(Flood Fill) 深度优先搜索的解题详细介绍,点击 有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 ...

  3. 分清<url-pattern>/</url-pattern>与<url-pattern>/*</url-pattern>的不同

    在写springMVC配置web.xml的时候会碰到下面有时候写/,有的时候又写/: 那么这两者有什么区别呢?我现在进行一些讲解: 1.当配置<url-pattern>/</url- ...

  4. 从SpringBoot构建十万博文聊聊限流特技

    前言 在开发十万博客系统的的过程中,前面主要分享了爬虫.缓存穿透以及文章阅读量计数等等.爬虫的目的就是解决十万+问题:缓存穿透是为了保护后端数据库查询服务:计数服务解决了接近真实阅读数以及数据库服务的 ...

  5. C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性

    系列目录     [已更新最新开发文章,点击查看详细] 本篇主要介绍如何获取单文件/模型下单个构建的属性信息. 请求地址:GET https://api.bimface.com/data/v2/fil ...

  6. POJ-2155-Matrix二位树状数组应用

    题目: 一个只有0和1构成的二维平面,给你两种指令,一种是区间的更新,即0变为1,1变为0:一种是查询一个点是1还是0: 由于是二进制,所以每次更新在相应的点上加一,最后对2取余即可. 至于二维的树状 ...

  7. Kth Minimum Clique_2019牛客暑期多校训练营(第二场)

    题目连接: https://ac.nowcoder.com/acm/contest/882/D Description Given a vertex-weighted graph with N ver ...

  8. 模板汇总——splay

    #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] ; , root; struct Node{ ], pre, sz; void init ...

  9. 2018中国大学生程序设计竞赛 - 网络选拔赛 hdu Tree and Permutation 找规律+求任意两点的最短路

    Tree and Permutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  10. List集合的排序

    最近在写需求时,将某张表中的短信信息拿出,sql写完后,取出来后的结构是List<Map>,在进行到某一步时需要将这个List<Map>进行逆序排序, 当时第一想法便是写一个f ...