想建一个自己的网站,用模板怎么做网站,搜索引擎优化的含义,企业的网站做一个要多少目录
一、堆的核心概述
#xff08;一#xff09;概述
#xff08;二#xff09;堆空间细分
#xff08;三#xff09;jvisualvm工具
二、设置堆内存的大小与OOM
三、年轻代与老年代
四、图解对象分配一般过程
五、对象分配特殊过程
六、常用调优工具
七、Mino…目录
一、堆的核心概述
一概述
二堆空间细分
三jvisualvm工具
二、设置堆内存的大小与OOM
三、年轻代与老年代
四、图解对象分配一般过程
五、对象分配特殊过程
六、常用调优工具
七、MinorGCMajorGCFullGC
一MinorGC的触发条件
二老年代GCMajorGC/FullGC触发条件
三FullGC的触发条件
八、内存分配策略
九、为对象分配内存TLAB
十、小结堆空间的参数设置
十一、堆是分配对象的唯一选择吗
逃逸分析
1、栈上分配
2、同步策略
3、分离对象或标量替换 这次学习的是JVM运行时数据区中的堆内存 一、堆的核心概述
一概述
1、一个JVM实例只存在一个堆内存堆也是Java内存管理的核心区域
2、Java堆区在JVM启动的时候即被创建其空间大小也就确认了。堆内存的大小是可调节的可以通过参数调节堆的最大内存和初始内存等
3、Java虚拟机规范规定堆可以处于物理上不连续的内存空间中但在逻辑上它应该被视为连续的这里涉及虚拟内存的概念。
4、所有的线程共享Java堆在这里还可以划分线程私有的缓冲区TLAB
5、“几乎”所有的对象实例都在堆上分配内存为什么是“几乎”后面会讲到逃逸分析
6、数组和对象可能永远不会存储在栈上因为栈帧中保存引用引用指向对象或者数组在堆中的位置为什么是“可能”逃逸分析可能直接在栈上为对象分配空间而不用在堆上开辟空间了
7、方法结束后堆中的对象不会马上被移除仅仅在垃圾收集的时候才会被移除。堆是GC执行垃圾回收的重点区域
二堆空间细分
Java7及之前内存逻辑上分为
新生区 Eden区Survivor区 fromto 谁空谁是to养老区永久区
Java8及之后内存逻辑上分为
新生区 Eden区Survivor区 fromto 谁空谁是to养老区元空间 不同书籍叫法不一样看到这些名词知道是同个意思就可以了 新生区新生代年轻代养老区老年区老年代永久区永久代 三jvisualvm工具
可以通过cmd命令行jvisualvm开启然后在菜单栏工具中安装插件后可以查看GC情况 二、设置堆内存的大小与OOM
1、-XX:PrintGCDetails可开启打印查看方法区实现
2、-Xms 小秘书表示堆空间的起始内存。
3、-Xmx小明星表示堆空间的最大内存 超过最大内存将抛出OOM 通常将-Xms和-Xmx两个参数配置相同的值其目的是为了能够在java垃圾会后清理完堆区后不需要重新分隔计算堆区的大小从而提高性能 默认情况下初始内存大小为物理电脑内存大小/64。最大内存大小为物理电脑内存/4 4、cmd命令
jps命令 查看当前程序运行的进程
jstat 查看JVM在gc时的统计信息 jstat -gc 进程号
三、年轻代与老年代
Java对象划分为两类生命周期短和长的。
新生代与老年代空间默认比例1:2可以通过设置参数来控制
-XX:NewRatio2表示新生代占1老年代占2新生代占整个堆的1/3 ratio比率比例的意思
jinfo -flag 关键词 进程号查看参数设定值
在HotSpot中Eden空间和另外两个Survivor空间缺省所占的比例是8:1:1 -XX:SurvivorRatio调整这个空间比例Eden与Survivor区的比例 实际是6:1:1因为有自适应机制 -XX:-UseAdaptiveSizePolicy-表示关闭自适应实际没有用。直接用Ratio分配即可
几乎所有的Java对象都是在Eden区被new出来的。
Eden放不了的大对象直接进入老年代了。
IBM研究表明新生代80%的对象都是朝生夕死
-Xmn洗面奶设置新生代最大内存大小如果同时设置了新生代比例与此参数冲突则以此参数为准。 hotspot为什么要分为新生代和老年代 因为分代的唯一理由就是优化GC的性能。大多数的对象都是朝生夕死如果没有进行分代那所有的对象都在一块GC的时候要找到哪些对象可以回收就需要对所有对象都进行扫描性能开销较大。而如果分代的话新创建的对象放到某一地方当GC的时候先把这块存储“朝生夕死”对象的区域进行回收这样就能够以较高的效率释放空间。 设置比例不同可能导致的结果 1新生代设置过小 一是新生代GC次数非常频繁增大系统消耗二是导致大对象直接进入旧生代占据了旧生代剩余空间诱发Full GC 2新生代设置过大 一是新生代设置过大会导致老年代过小堆总量一定从而诱发Full GC二是新生代GC耗时大幅度增加 一般说来新生代占整个堆1/3比较合适 3Survivor设置过小 导致对象从eden直接到达旧生代降低了在新生代的存活时间 4Survivor设置过大 导致eden过小增加了GC频率 另外通过-XX:MaxTenuringThresholdn来控制新生代存活时间尽量让对象在新生代被回收 四、图解对象分配一般过程
1、new的对象先放在Eden区此区有大小限制
2、当创建新对象Eden空间填满时会触发Minor GC将Eden不再被其他对象引用的对象进行销毁。再加载新的对象放到Eden区
3、将Eden中剩余的对象移到幸存者0区
4、再次触发垃圾回收此时上次幸存者下来的放在幸存者0区的如果没有回收就会放到幸存者1区
5、再次经历垃圾回收又会将幸存者重新放回幸存者0区依次类推
6、可以设置一个次数默认是15次超过15次则会将幸存者区幸存下来的转去老年区
-XX:MaxTenuringThresholdN进行设置 总结 针对幸存者s0s1区的总结复制之后有交换谁空谁是to 频繁在新生区收集很少在养老区收集几乎不在永久区/元空间搜集 五、对象分配特殊过程 触发YGC幸存者区就会进行回收不会主动进行回收
超大对象eden放不下就要看Old区大小是否可以放下。如果Old区放得下就直接放到Old区。如果也放不下需要FullGCMajorGC这两GC概念还是有区别的。下面详解 六、常用调优工具
JDK命令行EclipseMemory Analyzer ToolJconsoleVisualVMJprofilerJava Flight Recorder
七、MinorGCMajorGCFullGC
针对 HotSpot VM 的实现它里面的 GC 其实准确分类只有两大种
部分收集 (Partial GC)
新生代收集Minor GC / Young GC只对新生代进行垃圾收集老年代收集Major GC / Old GC只对老年代进行垃圾收集。需要注意的是 Major GC 在有的语境中也用于指代整堆收集混合收集Mixed GC对整个新生代和部分老年代进行垃圾收集。
整堆收集 (Full GC)收集整个 Java 堆和方法区。
一MinorGC的触发条件
当年轻代空间不足时就会触发MinorGC这里的年轻代指的是Eden满Survivor满不会触发GC。每次MinorGC会清理年轻代的内存
因为Java对象大多朝生夕灭所以MinorGC非常频繁。MinorGC会引发STWstop the world即停止用户线程让GC线程运行
二老年代GCMajorGC/FullGC触发条件
指发生在老年代的GC对象从老年代消失我们说“MajorGC”“FullGC”发生了
出现了MajorGC经常会伴随至少一次MinorGC
但是并非绝对在Parallel Scavenge收集器的收集策略里就直接进行MajorGC的策略选择过程也就是老年代空间不足会先尝试触发MinorGC如果之后空间还不足则触发MajorGC
MajorGC的速度比MinorGC慢10倍以上STW的时间更长
如果MajorGC后内存还不足就报OOM了
三FullGC的触发条件
1、调用System.gc()时系统建议执行FullGC但是不必然执行
2、老年代空间不足
3、方法区空间不足
4、通过MinorGC后进入老年代的平均大小大于老年代的可用内存
5、由Eden区Survivor 0区向Survivor 1区复制时对象的大小大于ToSpace可用内存则把改对象转存到老年代且老年代的可用内存小于该对象的大小
FullGC是开发或调优中尽量要避免的这样暂停时间会短一些。
八、内存分配策略
1、如果对象再Eden出生并经过第一次MinorGC后仍然存活并且能被Survivor区容纳则被移动到Survivor空间中并将对象年龄设置为1对象再Survivor区每熬过一次MinorGC年龄就1当年龄增加到一定程度默认为15不同JvmGC都所有不同时就会被晋升到老年代中
可以通过参数 -XX:MaxTenuringThreshold 设置阈值
2、如果大对象Eden放不下会直接分配到老年代
我们应尽量避免程序中出现过多的大对象
3、动态对象年龄分配
如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半年龄大于或等于该年龄的对象可以直接进入老年代无需等到MaxTenuringThreshold中要求的年龄 4、空间分配担保机制
在发生Minor GC之前虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间 如果大于则此次MinorGC是安全的如果小于则查看-XX:HandlePromotionFailure设置是否允许担保失败 true 会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小大于则尝试进行一次MinorGC但是这次MinorGC依然是有风险的小于则改为进行一次FullGCfalse 则改为进行一次FullGCjdk6update24之后这个参数不会再影响到虚拟机的空间分配担保策略。规则改为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行MinorGC否则进行FullGC 通过 -XX:HandlePromotionFailuretrue/false 进行设置是否允许担保失败 九、为对象分配内存TLAB
堆区是线程共享区域任何线程都可以访问到堆区的共享数据。由于对象实例的创建在JVM中非常频繁因此在并发环境下从堆区中划分内存空间是线程不安全的。为避免多个线程操作同一地址需要使用加锁等机制进而影响分配速度。
于是TLAB(Thread Local Allocation Buffer)出现了
从内存模型而不是垃圾收集的角度对Eden区域进行划分JVM为每个线程分配了一个私有缓存区域包含在Eden空间中
多线程同时分配内存时使用TLAB可以避免一系列的非线程安全问题同时还能够提升内存分配的吞吐量因此我们将这种内存分配方式称为快速分配策略 1、尽管不是所有的对象实例都能够在TLAB中成功分配内存但是JVM确实是将TLAB作为内存分配的首选 2、开发人员通过-XX:UseTLAB设置是否开启TLAB空间 3、默认情况下TLAB空间内存非常小仅占有整个Eden空间的1%通过-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden空间的百分比大小 4、一旦对象在TLAB空间分配内存失败JVM就会尝试通过使用加锁机制确保数据操作的原子性从而直接在Eden空间中分配内存 十、小结堆空间的参数设置 十一、堆是分配对象的唯一选择吗
随着JIT编译器的发展与逃逸分析技术逐渐成熟栈上分配、标量替换优化技术将会导致一些微秒变化所有对象分配到堆上渐渐变得不那么绝对了。
有一种特殊情况如果经过逃逸分析后发现一个对象并没有逃逸出方法的话那么就可能被优化成栈上分配这样无需堆上分配也不需要垃圾回收了也是最常见的堆外存储技术
逃逸分析
逃逸分析的基本行为就是分析对象动态作用域
当一个对象在方法中定义后对象只在方法内部使用则认为没有发生逃逸当一个对象在方法中被定义后它被外部方法引用则认为发生逃逸例如作为调用参数传递到其他地方中 1、栈上分配
如果未发生逃逸将堆分配转为栈分配如果一个对象在子程序中被分配要使指向该对象的指针永远不会逃逸对象可能是栈分配的候选而不是堆分配
2、同步策略
如果一个对象被发现只能从一个线程被访问到对于这个对象的操作可以不考虑同步
JIT编译器可以借助逃逸分析来判断同步块所使用的的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果没有那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步。这样就大大提高并发性和性能这个取消同步的过程就叫同步省略也叫锁消除 3、分离对象或标量替换
有的对象可能不需要作为一个连续的内存结构存在也可以被访问到那么对象的部分或全部可以不存储在内存。而是存储在CPU寄存器中
标量是指一个无法再分解的更小的数据的数据。Java中原始数据类型就是标量
可以分解的数据叫聚合量Java中的对象就是聚合量因为他可以分解成其他聚合量和标量 标量替换参数-XX:EliminateAllocations默认打开