热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[Java]JVM学习笔记

[Java]JVM学习笔记-JVM学习笔记在极客时间学习课程时,李智慧老师分享了关于新技术学习方法的经验,叫做“5-20-2”法。解释一下,就是在学习一项新技术时:要在5

JVM学习笔记

在极客时间学习课程时,李智慧老师分享了关于新技术学习方法的经验,叫做“5-20-2”法。

解释一下,就是在学习一项新技术时:

  • 要在5分钟之内了解他是解决了什么问题,相比竞品技术有什么优势;
  • 在20分钟之内,了解这项技术在解决这些问题的时候用了哪些思路,哪些新颖方法;
  • 在2个小时之内,试着做一些demo快速上手。

如果能做到这些,就对这项技术进行一个持续的深挖,如果解决不了这些问题,就及早收手,免得过多浪费时间。

为了试验上述方法的可行性,以JVM为切入点,我开始有意识的训练自己在短时间内对新技术的学习。虽然时间上失败了,用了10个小时,才对JVM有个大概的印象。(效率较低,有待训练),但是这种以终为始,强迫自己“走马观花”的方法,很适合快速掌握新技术的知识框架。

以下就是关于JVM问题点的整理。

JVM主要解决了哪些问题

  • 实现代码的不同平台可移植性
  • 内存的动态分配
  • 垃圾自动回收

JVM如何解决的这些问题

可移植性

Java代码,根据不同平台,编译出对应的机器码;

这部分需要掌握的知识点:

  • 类文件的结构
  • 类加载机制
  • 代码执行机制

注:这部分不展开,后续填充内容。

内存动态分配

这部分需要掌握的知识点:

  • Java代码都有哪些内容需要加载到内存中
  • JVM中都有哪些区域,每个区域的作用是什么
  • 不同区域之间如何联动

问题1:JVM都会加载哪些信息

需要记入内存的内容包括:类、数据类型、实例化的对象,程序执行状态(执行到的位置)等。

问题2:JVM的内存模型(都有哪些区域、作用)

所有线程共享:

  • 方法区:又称为永久代、元数据区metaSpace(JDK1.8之后)。指代的一个事情。

用于存储虚拟机加载的类信息、常量、静态变量。

  • 静态常量池存储在方法区。
  • 永久代的垃圾收集是和老年代(old generation)捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。
  • 堆:OOM重灾区

用于存放实例化的对象。

主要包含:
  • 新生代:又包括Eden区域和Survivor区域,From和To区域均属于Survivor区域(还有一种称呼是Survivor0和Survivor1)。

  • 老年代:主要用于“年龄”超过15的对象(转移年龄可设置),以及需要连续内存空间的大对象;

资源分配习惯:
  • Young和Old区域比例为1:2
  • Eden和Survivor0区域比例为8:1 ,这样就可以保障Young新生代10等分。
区域划分的原因:

为了在不同区域执行不同的GC算法,根据不同对象的生命周期,选择不同的GC算法,有利于效率最大化。

对象转移机制:
  • 对象被创建,存储在Eden区;
  • 初次Minor GC后依然存活,转移到Survivor区域;
  • 每次GC 后仍存活,年龄+1;
  • 到达15岁(默认值,参数可设置)之后,转移到Old区;
  • 如果大对象创建时,需要联系内存空间,Eden不满足时直接在Old区域创建。

堆内存划分示意图:

注:新生代存储中,除了Eden外,叫做Survivor区域;由于Survivor区域采用复制内存回收的方法,所以平均分为两份,一般称为Survivor0和Survivor1,互为内存迁移目的。

所以Eden 和Survivor0的比例设置为8:1 。

线程私有:

  • 虚拟机栈(VM Stack)

描述Java方法执行,每个方法被执行时创建一个“栈针”,

会出现OverOutStack(栈溢出)

主要包含:
  • 操作数栈:
  • 局部变量表:用于记录方法的局部变量,注:是引用,不是真实对象
  • 帧数据区
  • 本地方法栈(Native Method Stack)

该区域主要是为JVM的方法(Native Function)服务。这个区域不用考虑。

  • 程序计数器(Program Counter Register)

JVM中最小的区域,记录当前程序所执行字节码的行号指示器。记录程序执行到的当前位置。

问题3:不同区域之间如何联动

注:待完善

垃圾自动回收(GC)

问题:

  • 都有哪些内存区域需要被回收
  • 怎么判断要不要回收
  • 如何回收内存,常见GC算法
  • 不同区域的GC算法

问题1:都有哪些区域的内存会GC

  • 新生代(Young):堆内存一部分
  • 老年代(Old):堆内存一部分
  • 永久代(MetaSpace):方法区

问题2:如何判断当前对象要不要被回收

传统说是对象引用法。并不准确,会出现两个无用对象互相引用的方法,导致两个对象引用数都大于0,无法被GC。

目前JDK采用:可达性分析,有向图算法,从Root Object连接不到的对象,都被GC。

VM栈中对象可以被理解为Root Object,进行向下搜索。

问题3:常见的GC算法

  • 标记清除算法:标记无用Ob,进行清除。缺点是会产生大量碎片空间。
  • 标记整理压缩算法:对对象进行标记,进行内存区域整理合并;
  • 复制算法:两个相同的区域,将区域1中内存整理后,全部放置在区域2中;
  • 分代收集算法。

问题4:不同区域GC算法

Eden:问题点。

Survivor:标记-复制算法

Old & MetaSpace:一般使用CMS收集算法

Full GC:Old区或者MetaSpace满了之后,会触发,导致JVM全部暂停。Stop the world

问题5:垃圾收集器概念

Serial:

ParNew:

Parallel:

CMS:并发-标记-清除算法,以牺牲吞吐量来换取最短回收停顿时间的算法。(分线程进行标记清理)

G1:并行标记,分代收集,空间整理,可预测停顿。(没搞懂,待定)

注:当Old区域的剩余空间小于平均大小,就会触发Full GC,又称为“Stop the world”。整个JVM全部停止,完成内存资源回收。Old区域GC资源消耗大,应该尽量避免生命周期较短的大对象。

使用的工具

JVM配置项

内存区域大小配置:

通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区(永久代)的大小。

-XX:+UseConcMarkSweepGC:设置CMS GC算法

-Xss:设置栈内存
-Xmn:设置年轻代内存,(Eden + Survivor)
-XX:SurvivorRatio=8:设置Eden和Survivor比例为8:1
-XX:PretenureSizeThreshold:设置大对象阈值,超过这个值就放置在Old区域

-Xms:堆内存的最小大小,默认为物理内存的1/64

-Xmx:堆内存的最大大小,默认为物理内存的1/4

-Xmn:堆内新生代的大小。通过这个值也可以得到老生代的大小:-Xmx减去-Xmn

GC配置:

设置OOM时打印dump文件。
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=file_path

修改GC收集器为cms
-XX:+UseConcMarkSweepGC

垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails:console显示GC详细信息
-XX:+PrintGCTimeStamps
-Xloggc:filename

OOM

堆内存溢出

java.lang.OutOfMemoryError: Java heap space

  • 要根据Dump文件,判断哪个区域内存溢出,相应的修改代码逻辑,查看是否有废弃对象,未放开引用。
  • 适当调整JVM参数。

栈内存溢出

java.lang.OutOfMemoryError.StackOverflowError

程序所要求的栈深度过大导致,可以写一个死递归程序触发。

永久代溢出

OutOfMemoryError: PermGen space

持久带中包含方法区,方法区包含常量池。

因此持久带溢出有可能是(1) 运行时常量池溢出,也有可能是(2)方法区中保存的Class对象没有被及时回收掉或者Class信息占用的内存超过了我们配置。

注:实战出真知,理论学习都是入门。

无法创建本地线程

Caused by: java.lang.OutOfMemoryError:unable to create new native thread

系统内存的总容量不变,堆内存、非堆内存设置过大,会导致能给线程分配的内存不足。

常用工具

JVM分析工具

  • Jps:查看当前Java进程,及进程号
  • 使用jmap工具分析
C:\Users\Yanru>jmap -J-d64 -heap 30284(PID)
Attaching to process ID 30284, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.201-b09
using parallel threads in the new generation.  ##新生代采用的是并行线程处理方式
using thread-local object allocation.  
Concurrent Mark-Sweep GC   ##同步并行垃圾回收
Heap Configuration:  ##堆配置情况,也就是JVM参数配置的结果[平常说的tomcat配置JVM参数,就是在配置这些]
   MinHeapFreeRatio = 40 ##最小堆使用比例
   MaxHeapFreeRatio = 70 ##最大堆可用比例
   MaxHeapSize      = 2147483648 (2048.0MB) ##最大堆空间大小
   NewSize          = 268435456 (256.0MB) ##新生代分配大小
   MaxNewSize       = 268435456 (256.0MB) ##最大可新生代分配大小
   OldSize          = 5439488 (5.1875MB) ##老年代大小
   NewRatio         = 2  ##新生代比例
   SurvivorRatio    = 8 ##新生代与suvivor的比例
   PermSize         = 134217728 (128.0MB) ##perm区 永久代大小
   MaxPermSize      = 134217728 (128.0MB) ##最大可分配perm区 也就是永久代大小
Heap Usage: ##堆使用情况【堆内存实际的使用情况】
New Generation (Eden + 1 Survivor Space):  ##新生代(伊甸区Eden区 + 幸存区survior(1+2)空间)
   capacity = 241631232 (230.4375MB)  ##伊甸区容量
   used     = 77776272 (74.17323303222656MB) ##已经使用大小
   free     = 163854960 (156.26426696777344MB) ##剩余容量
   32.188004570534986% used ##使用比例
Eden Space:  ##伊甸区
   capacity = 214827008 (204.875MB) ##伊甸区容量
   used     = 74442288 (70.99369812011719MB) ##伊甸区使用
   free     = 140384720 (133.8813018798828MB) ##伊甸区当前剩余容量
   34.65220164496263% used ##伊甸区使用情况
………………
  • jmap -dump:format=b,file=idea.bin 22128

生成22128进程的JVM状态文件。

  • jstat:查看本地类和远端JVM的运行状况

在没有可视化终端排查问题的首选。针对13224进程,没250毫秒查询一次,查询20次。

C:\Users\Yanru>jstat -gc 13224 250 20
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
10240.0 10240.0  0.0    0.0   81920.0  35945.2   102400.0     0.0     4480.0 775.8  384.0   76.4       0    0.000   0      0.000    0.000
  • jinfo UID:查看线程的JVM属性

VM Flags: Non-default VM flags: -XX:CICompilerCount=4 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=null -XX:InitialHeapSize=31457280 -XX:MaxHeapSize=52428800 -XX:MaxNewS …………

  • jmc:可视化JVM检测工具

  • jconsole:Java监视管理控制台

可以查看堆内存各区域大小。

JVM监控工具

  • Jconsole:可以查看本地的Jvm dump文件

  • VisualVM:大一统的可视化监控工具

JVM调优策略

<待更新>

常见面试题

<待更新>

当然,上述这项提纲性质的内容,对JVM这项庞大且应用广泛的技术,恐怕连入门都算不上,最多算是自己理解这项技术的技能树,后续遇到问题,再在对应的区域填充知识。

这个思维架构类似于《神探夏洛克》中的记忆宫殿


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • Mono为何能跨平台
    概念JIT编译(JITcompilation),运行时需要代码时,将Microsoft中间语言(MSIL)转换为机器码的编译。CLR(CommonLa ... [详细]
  • mysqldinitializeconsole失败_mysql03误删除了所有用户解决办法
    误删除了所有用户解决办法第一种方法(企业常用)1.将数据库down掉[rootdb03mysql]#etcinit.dmysqldstopShuttingdownMySQL..SU ... [详细]
author-avatar
哎呦我去2502859031
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有