栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

jvm 堆

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

jvm 堆

1、jvm堆

今天我们只说java的堆。java虚拟机其实由很多部分组成,而堆只是其中一部分,但是也是很重要的一部分。尤其是面试经常会问!堆的核心概述(注意“可能”、“几乎”这几个关键字,后面会谈到)

1)、一个JVM实例只存在一个堆内存,堆也是java内存管理的核心区域。
2).java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间。(堆内存的大小是可以调节的)
3).《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。
4).所有的线程共享java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer, TLAB)。
5).《java虚拟机规范》中对java堆的描述是:所有的对象实例以及数组都应当在运行时分配在堆上。(The heap is the run-time data area from which memory for all class instances and arrays is allocated) 我要说的是:“几乎”所有的对象实例都在这里分配内存。——从实际使用角度看的。
6).数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置。
7).在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。
8).堆,是GC(Garbage Collection,垃圾收集器)执行垃圾回收的重点区域。

2、举例

字节码文件,new关键字就是在堆中开辟了一块空间。(堆创建对象,栈引用类型变量指向堆,方法区存放类及其方法实现)



3、堆的内存细分结构

现在垃圾收集器大部分都基于分代收集理论设计,堆空间细分为: (1)java7及之前堆内存逻辑上分为三部分:新生区+养老区+永久区 Young Generation Space,新生区,Young/New 又被划分为Eden区和Survivor区
Tenure generation space,养老区,
Old/Tenure Permanent Space,永久区,Perm

java8及之后堆内存逻辑上分为三部分:新生区+养老区+元空间 Young Generation Space,新生区,Young/New 又被划分为Eden区和Survivor区 Tenure generation space,养老区,Old/Tenure Meta Space,元空间,Meta 约定:新生区<=>新生代<=>年轻代;养老区<=>老年区<=>老年代;永久区<=>永久代

4、设置堆内存大小

.java堆区用于存储java对象实例,那么堆的大小在JVM启动时就已经设定好了,大家可以通过选项“-XMx”和“-Xms”来进行设置(新生代+老年代)。 “-Xms”用于表示堆区的起始内存,等价于-XX:InitialHeapSize “-Xmx”则用于表示堆区的最大内存,等价于-XX:MaxHeapSize -X 是jvm运行参数 ms 是memory start
一旦堆区中的内存大小超过“-Xmx”所指定的最大内存时,将会抛出OutOfMemoryError异常。
通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能。
默认情况下,初始内存大小:物理电脑内存大小 / 64;最大内存大小:物理电脑内存大小 / 4
查看设置的参数:方式一,jps ->jstat -gc 进程id;方式二,-XX:+PrintGCDetails

例如(默认是b,大小写皆可):
-Xms1024
-Xms6166k
-Xms60m
-XX:InitialHeapSize=1024k

代码获取堆内存信息(假如说配置了jvm600M,用代码只能得出575M,说明有25M是s1或s0区,因为这两个区域只能同时使用一个):


使用-XX:+PrintGCDetails参数,可以查看堆信息打印。(可以对比jstat -gs,查看堆信息,这两种方式是一样的)(-XX:+PrintGCDetails打印的新生代total,from和to区,只算一个,因为同一时间只会用到一个)


(后面有使用jstat详细方法)

五、OOM举例

六、年轻代和老年代

1)存储在JVM中的java对象可以被划分为两类: 一类是生命周期较短的瞬时对象,这类对象的创建和消亡都非常迅速。 另外一类对象的生命周期却非常长,在某些极端的情况下还能够与JVM的生命周期保持一致。
2)java堆区进一步细分的话,可以划分为年轻代(YoungGen)和老年代(OldGen)。
3)其中年轻代又可以划分为Eden空间、Survivor0空间和Survivor1空间(有时也叫作from区、to区)。

七、配置新生代与老年代在堆结构的占比

这个参数开发中一般不会去调,如果明确知道很多对象生命周期比较长,可以将老年代调大
默认-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的1/3。
可以修改-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/5。


在HotSpot中。Eden空间和另外两个Survivor空间缺省所占的比例是8:1:1,当然开发人员可以通过选项“-XX:SurvivorRatio”调整这个空间比例。比如-XX:SurvivorRatio=8

jvm有个自适应的机制,可能配置了比例为8,但是实际上用工具看到的仍然是6:1:1,可以这样关掉自适应内存分配策略:-XX:-UseAdaptiveSizePolicy

几乎所有的java对象都是在Eden区被new出来的。

绝大部分的java对象的销毁都在新生代进行了。
IBM公司的专门研究表明,新生代中80%的对象都是“朝生夕死”的。

可以使用选项“-Xmn”设置新生代最大内存大小。
这个参数一般使用默认值就可以了,直接设置比例即可,否则会跟“-XX:SurvivorRatio”冲突。

八、对象分配过程

对象分配过程概述
为新对象分配内存是一件非常严谨和复杂的任务,JVM的设计者们不仅需要考虑内存如何分配、在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC执行完内存回收后是否会在内存空间中产生内存碎片。
new的对象先放伊甸园区。此区有大小限制。
当伊甸园的空间填满时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。再加载新的对象放到伊甸园区。
然后将伊甸园区中的剩余对象移动到幸存者0区。
如果再次触发垃圾回收,此时上次幸存下来的放到幸存者0区的对象,如果没有回收,就会放到幸存者1区。
如果再次经历垃圾回收,此时会重新放回幸存者0区,接着再去幸存者1区。
啥时候能去养老区呢?可以设置次数。默认是15次。 · 可以设置参数:-XX:MaxTenuringThreshold=进行设置。
在养老区,相对悠闲。当养老区内存不足时,再次触发GC:Major GC,进行养老区的内存清理。
若养老区执行了Major GC之后发现依然无法进行对象的保存,就会产生OOM异常。

注意:eden区满了之后会触发YGC/Minor GC,同时带着Survivor区GC。而Survivor区满了并不会触发GC,这并不意味着Survivor区不会GC,而是它的GC是eden区满了之后才会触发GC。Survivor区满了,对象会直接从eden区直接到老年代或者没有满15次直接到老年代(视情况而定,下面会提到)。


总结 1.针对幸存者s0,s1区的总结:复制之后有交换,谁空谁是to。 2.关于垃圾回收:频繁在新生区收集,很少在养老区收集,几乎不再永久区/元空间收集。 对象分配特殊情况

九 对象分配特殊情况

十、对象分配过程演示(后面附有jvisualvm使用方法)


十、Minor GC、Major GC与Full GC

1)JVM在进行GC时,并非每次都对上面三个内存(新生代、老年代;方法区)区域一起回收的,大部分时候回收的都是指新生代。
2)针对HotSpot VM的实现,它里面的GC按照回收区域又分为两大种类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC)。

2.1部分收集:不是完整收集整个java堆的垃圾收集。其中又分为:
2.1.1新生代收集(Minor GC / Young GC):只是新生代(Eden、s0、s1)的垃圾收集。
2.1.2老年代收集(Major GC / Old GC):只是老年代的垃圾收集。 目前,只有CMS GC会有单独收集老年代的行为。 注意,很多时候Major GC会和Full GC混淆使用,需要具体分辨是老年代回收还是整堆回收。
2.1.3混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集。 目前,只有G1 GC会有这种行为。

2.2整堆收集(Full GC):收集整个java堆和方法区的垃圾收集。

十一、最简单的分代式GC策略的触发条件

1).年轻代GC(Minor GC)触发机制: 当年轻代空间不足时,就会触发Minor GC,这里的年轻代满指的是Eden代满,Survivor满不会引发GC。(每次Minor GC会清理年轻代的内存。) 因为java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快,这一定义既清晰又易于理解。 Minor GC会引发STW(stop the word),暂停其他用户的线程,等垃圾回收结束,用户线程才恢复运行。
2).老年代GC(Major GC/Full GC)触发机制: 指发生在老年代的GC,对象从老年代消失时,我们说“Major GC”或“Full GC”发生了。 出现Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。 也就是在老年代空间不足时,会尝试触发Minor GC。如果之后空间还不足,则触发Major GC。 Major GC的速度一般会比Minor GC慢10倍以上。STW的时间更长。 如果Major GC后,内存还不足,就报OOM了。

3).Full GC触发机制:(后面会细说) 触发Full GC执行的情况有以下五种:
(1)调用System.gc()时,系统建议执行Full GC,但是不必然执行。
(2)老年代空间不足
(3)方法区空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存。
(5)由Eden区、survivor space0(From Space)区向survivor space1(To Space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。 说明:full GC是开发或调优中尽量要避免的。这样暂时时间会短一些。 实例 (使用-XX:+PrintGCDetails,会打印GC情况)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/891135.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号