前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM学习一

JVM学习一

作者头像
路行的亚洲
发布2020-07-19 21:15:01
3550
发布2020-07-19 21:15:01
举报
文章被收录于专栏:后端技术学习后端技术学习

JVM学习一

jvm的内存结构、相关的垃圾算法、分代回收算法、相关溢出的问题排查思路

jvm的内存结构:可以看到我们的java文件会首先编译成class文件,经过类加载器进行加载,然后经过jvm的相关区域:f方法区、堆、虚拟机栈、程序计数器、本地方法栈等地,可以进行本地方法接口进行调用,执行引擎,进行编译,执行程序。当中涉及到垃圾回收。

1.程序计数器:Program Count Register

寄存器,记住下一条jvm指令的执行地址,是线程私有的,JVM中唯一不会存在内存溢出的。

2.虚拟机栈:Java Virtual Mechinal Stacks

每个线程只能有一个活动栈帧,通常是参数、局部变量、返回地址,对应着当前正在执行的那个方法

栈帧:每个方法运行时需要的内存。

垃圾回收设计栈内存吗?不涉及栈内存。

栈内存的分配越大越好吗?

不是的,通常是默认的,1024k,其中linux和mac电脑默认是1024k,而windows是根据系统而定。由于一个线程对应一个栈帧,如果越大,则会拖慢虚拟机的运行性能。

方法内的局部变量是否线程安全?

如果方法内的局部变量没有逃离方法的作用访问,则它是线程安全的,如果局部变量应用了对象,并逃离方法的作用范围,则需要考虑线程安全的问题。也即与变量的作用域有关。

栈内存溢出:栈帧过多、过大都会导致栈内存溢出。

栈内存溢出的排查方法:

首先采用top命令,查看当前是哪个进程cpu占用过高

接着采用ps H -eo pid,tid,%cpu |grep 进程id

用jstack 进程id排查到有问题线程,定位到问题代码的行号,从而解决问题。

3.本地方法栈:Native Method Stacks

主要存放操作系统的方法,存放native方法的内存调用。

4.堆:Heap

通过new关键字创建的对象都会被存放在堆内存中。它是线程共享的,堆中对象都需要考虑线程安全的问题,同时有垃圾回收机制。

堆溢出问题解决:

通常会出现java.lang.OutofMemoryError:java heap space的错误信息。

首先通过jps查看到当前有哪些java进程在运行。

接着采用jmap查看堆使用情况,通常jmap只能查看某一时刻的信息。jmap -heap 进程id

jconsole工具可以以图形化界面看到相关的监控信息,做到连续监控。连接jconsole,打开其图形化界面,进行查看。

采用jvisualvm ,可以进行堆dump日志分析,排查问题。

5.方法区:Method Area

主要存放成员方法、方法、构造方法、运行时常量池(String Table)

虚拟机启动时被创建,逻辑上是堆的一部分。jdk1.7及以前,存放在永久代中。而jdk1.8的时候存放在metaspace中。

方法区jdk1.7的时候会出现溢出,但jdk1.8之后存放在metaspace元空间中,因此通常情况下不会出现内存溢出的情况。

方法区常量池:运行时常量池StringTable

常量池就是一张类似于hash一样的表。虚拟机指令根据这张表找到执行的类名、方法名、类、字面量等信息。当类文件被加载时常量信息会加载到运行时常量池中,并把里面的符号地址变成真实地址。

串池(调用intern方法就可以放入)中如果有的常量,则不会到常量池中去找,其加载策略是惰性的。常量池中的字符串是符号,第一次用到时才是对象。同时利用串池可以避免重复创建,节省内存。字符串拼接通常是在编译期优化的。

如果项目中常量信息较多,同时又有重复,则可以考虑串池进行调优。同时如果常量信息较多,也可以调大桶的个数,由于其本身就是一张表。-XX:stringTableSize=桶个数

6.直接内存:Direct Memory

操作系统内存,常用于NIO操作时,用于数据缓冲区,分配回收成本较高,但读写性能高,不受jvm内存回收管理。

分配与回收:使用unsafe对象完成直接内存的分配和回收,分配内存可以采用allocateMemory来进行分配内存,并且回收需要主动调用freeMemory方法。ByteBuffer的实现类内部使用了cleaner虚引用来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过clear的clean方法调用freeMemory来释放内存。

相关引用

强引用、软引用、弱引用、虚引用、终结器引用

强引用:只有所有GC roots对象都不通过强引用引用该对象,该对象才能被垃圾回收。

软引用:仅有软引用该对象,在垃圾回收后,内存还不足时会再次触发垃圾回收,回收软引用对象,可以配合引用队列来释放引用自身。

弱引用:仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象,可以配合引用队列来释放引用自身。

虚引用:必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会被徐引用入队,由Referencehandler线程调用虚引用相应的方法来释放直接内存。

终结器引用:无需手动编码,但器内部配合引用队列使用,在垃圾回收时,终结器引用入队,找到被引用对象并调用finalize方法,第二次GC回收的时候才能回收被引用对象。

垃圾回收

如何判断对象可以回收?采用可达性分析算法,也即没有引用的对象,通常会进行回收,也即孤立的对象会被回收。

垃圾回收算法:

通常可分为三种:标记清除mark sweep、标记整理mark compact、复制copy。

这三种算法:标记清除算法速度快,但产生内存碎片较多,不利于内存的充分使用。标记整理,速度适中,同时能够整理内存碎片。复制算法,速度最慢,但不会产生内存碎片,占用内存双倍。

由于三种算法都有其优点和缺点,因此需要综合使用它们。因此就产生了分带垃圾回收算法。

新生代由于产生的对象是朝生夕死的,因此通常会常用复制算法,而老年代则采用标记整理或标记清除算法。

同时可分为新生代、老年代、MetaSpace区(jdk1.7永久代)

新生代又可分为Eden区、Survivor区,而Survivor区又可分为From、To两部分。

对象存活区域:

1.通常首先分配在Eden区

2.新生代空间不足时,会触发minor gc,Eden区和from存活对象使用copy算法复制到to中,存活的对象年龄+1,并且交换from、to

3.minor gc会引发stop the world,暂停其他用户的线程,等垃圾回收结束,用户线程才回复运行

4.当对象寿命超过阀值时,会晋升到老年代,最大寿命是15(4bit)

5.当老年代空间不足时,会先尝试触发minor gc,如果空间不足,那么触发full gc,stw的时间更长

相关jvm参数:

堆初始化大小:-Xms

堆最大大小:-Xmx或-XX:MaxHeapSize=size

新生代大小:-Xmn或-XX:newSize=size+-XX:MaxNewSize=size

幸存区比例(动态):-XX:InittalSurvivorRatio=ratio和-XX:+UseAdaptiveSizePolicy

幸存区比例:-XX:SurvivorRatio=ratio

晋升阀值:-XX:MaxTenuringThreshold=threshold

晋升详情:-XX:+PrintTenuringDistribution

GC详情:-XX:+PrintGCDetails -verbose:gc

FullGC前MinorGC:-XX:+scavengeBeforeFullGC

垃圾回收器:

可以分为串行垃圾回收器、并行垃圾回收器、并发垃圾回收器、G1等

串行垃圾回收器:单线程、堆内存较小,适合个人电脑,-XX:+userSerialGC=Serial+SerialOld,串行新生代和老年代

并行垃圾回收器:多线程,吞吐量高,-XX:+UserParallelGC —— -XX:+UseParallelOldGC,-XX:GCTimeRatio=ratio,-XX:MaxGCPauseMillis=ms,-XX:ParallelgcThreads=n,并行GC,新生代和老年代,同时可以设置比例,响应时间、线程数等信息

并发垃圾回收器:多线程,响应时间短,-XX:+UseConcMarkSweepGC—— -XX:UseParNewGC——SerialOld,-XX:ParallelGCThreads=n—— -XX:Concgcthreads,-XX:CMSInitiatingOccupancyFranction=percent,-XX:+CMSScavengeBeforeRemark,包含信息并发新生代GC,串行Old,并发线程数,CMS比例,重新标记再清理

G1垃圾回收器:

使用场景:注重高吞吐量,低延迟的场景,默认的暂停目标是200ms。超大堆内存,会将堆划分为多个大小相等的Region,整体上标记+整理算法,两个区域之间采用复制算法。

相关参数:

-XX:+UseG1GC

-XX:G1HeapRegionsSize=size

-XX:MaxGCPauseMillis=time

垃圾回收阶段:

Young Collection、Mixed Collection、Young Collection+Concurrent Mark

Young Collection:会STW.

Young Collection+CM:在Young GC时会进行GC Root的初始化标记,老年代占用堆空间比例达到阀值时,进行并发标记,不会STW.

Mixed Collection:会对E、S、O进行全面垃圾回收,最终标记会STW,拷贝存活会STW

进行Full GC:相关代的FullGC

Young Collection跨代引用:新生代回收的跨代引用(老年大引用新生代)问题:卡表与Remebered Set,在引用变量时通过post-write barier+dirty card queue进行处理,同时concurrent refinement threads更新Remembered Set.

Remark:pre-write barrier + satb_mark_queue

通常调优需要考虑:内存、锁竞争、cpu占用、IO、代码这些层面上的调优。

通常最快的GC:

考虑不发生GC,也即查看FullGC前后的内存占用,考虑数据是否太多、数据表示是否太大、是否存在内存泄漏(变量的作用范围、是否存在软、弱引用、第三方缓存等)。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端技术学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM学习一
    • 1.程序计数器:Program Count Register
      • 2.虚拟机栈:Java Virtual Mechinal Stacks
        • 3.本地方法栈:Native Method Stacks
          • 4.堆:Heap
            • 5.方法区:Method Area
              • 6.直接内存:Direct Memory
                • 相关引用
                  • 垃圾回收
                    • 对象存活区域:
                      • 相关jvm参数:
                        • 垃圾回收器:
                          • G1垃圾回收器:
                            • 相关参数:
                              • 通常最快的GC:
                              相关产品与服务
                              Elasticsearch Service
                              腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档