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

https://www.cnblogs.com/mousycoder/p/11612448.html

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. 坚持就胜利

原文地址:https://www.cnblogs.com/jinanxiaolaohu/p/11614839.html

时间: 2024-10-21 00:07:46

[转帖]【JVM 知识体系框架总结】的相关文章

【JVM 知识体系框架总结】

JVM 内存分布 线程共享数据区: 方法区->类信息,静态变量 堆->数组对象 线程隔离区 虚拟机栈-> 方法 本地方法栈->本地方法库 native 堆.程序计数器 JVM 运行数据 程序计数器 线程隔离 ,比较小的内存空间,当前线程所执行的字节码的行号 线程是一个独立的执行单元,由 CPU执行 唯一没有 OOM 的地方,由虚拟机维护,所以不会出现 OOM 虚拟机栈 执行的是Java方法 方法的调用就是栈帧入虚拟机栈的过程 栈帧:局部变量表(变量) .操作数栈(存放a+b的结果

C语言知识体系框架

一张图剖析c语言主要知识结构,对在c中迷茫的人或是正在复习c的人来说,很有帮助.

jQuery基本知识体系图

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

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

好东西值得分享 ,这是网络上总结的一些开源的东西直接就拿过来了  .... Android通用流行框架大全 先把这张图放在这 ,先来谈一谈项目结构 .我喜欢将东西按模块来划分: 都知道module .它的应用非常方便 .对于一个项目刚开始开发时要考虑这个项目是由那些部分组成 lib_base  :包含各种Base基类 .如 BaseActivty  BaseFragment  BaseApplication   这是一些项目的开始基础. lib_ui:各种自定义UI ,或第三方ui .现在and

集合框架一(知识体系及常用方法)

知识体系 Collection接口 --List接口 --存储数据有序,可以存储重复元素 --ArrayList(主要实现类)底层以数组实现 --LinkedList:对于频繁进行插入删除操作 底层以链表实现 --Set接口 --存储数据无序,不能存储重复元素 --HashSet.LinkedHashSet.TreeSet Map接口:存储键值对数据 --HashMap.LinkedHashMap.TreeMap --Hashtable(子类:Properties) 方法(不加泛型) Colle

[转帖]一文读懂分布式架构知识体系(内含超全核心知识大图)

一文读懂分布式架构知识体系(内含超全核心知识大图) https://yq.aliyun.com/articles/721007?spm=a2c4e.11153959.0.0.2f464977X7lSdH 作者 | 晓土  阿里巴巴高级工程师 姊妹篇阅读推荐:<云原生时代,分布式系统设计必备知识图谱(内含22个知识点)> 导读:本文力求从分布式基础理论.架构设计模式.工程应用.部署运维.业界方案这几大方面,介绍基于 MSA(微服务架构)的分布式知识体系大纲,从而对 SOA 到 MSA 进化有着立

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

from:  https://zhuanlan.zhihu.com/p/21895647 作者:靳洪飞链接:https://zhuanlan.zhihu.com/p/21895647来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. Java Java是超高人气编程语言,拥有跨平台.面向对象.泛型编程等特性.在TIOBE编程语言排行榜中,连续夺得第一宝座,而且国内各大知名互联网公司,后端开发首选语言:非Java莫属.今天只是梳理下Java知识体系,后续会针对各类目有更

研究生期间知识体系规划 .

现在研二了,自然语言处理方向的.一直以来不清楚自己要进行怎样的知识体系,通过研一的学习和手头触及的一点事,慢慢理清了自己要进行的知识体系.这个知识体系有四个方面:专业基础方面,项目方面,论文方面,综合素质方面. 专业基础 专业基础第一点是java语言学习.传说中有些牛逼院校可能不是很注重编程语言学习,但结合我自身来看,好好学习一门语言很重要的.怎么进行java方面学习呢?第一个阶段,找一门java基础教程,认真走一遍.很多人到这以后就开始进行java某个应用方面进行发展了,学习框架.调用三方接口

一、如何构建自己的知识体系

构建可用的知识体系就要读书,书是有体系结构的. 何谓知识体系? 技术与技巧包括:计算机基础理论. 计算机模型:内存/IO/时钟/CPU... 专项技术领域:算法.数据挖掘.数据管理.智能推荐.搜索...... 语言与工具:语言与相关体系.开发工具,分析工具,代码管理工具.HTML/CSS/Ajax.常用框架与第三方类库. 调试与测试:调试方法和哲学.定位问题.BUG管理工具.单元测试.集成测试.性能测试.安全测试.兼容性测试与方法.JS/Ajax测试与方法.服务层测试.Web层测试. 网络与系统