这篇文章大概看了10分钟,内容如下:什么是JVM堆?Java对象是不是都放在堆上了?线程和堆的关系堆的内部结构面试题新生代和老年代如何设置堆的Size?新生代与老年代的比例设置Eden和survivor的比例常用参数对象分配黄金句:分配过程内存分配策略(或对象提升(promotion)规则):对象分配原则MinorGC,MajorGC,FullGCMinorGC触发机制OldgenerationGC(MajorGC/FullGC)触发机制:FullGC触发机制:如何解决OOM为什么要对Java堆进行分代?不分代就不能正常工作吗?什么是TLAB(快速分配策略)?为什么会有TLAB(ThreadLocalAllocationBuffer)快速分配策略?什么是TLAB?TLAB说明:什么是JVM堆一个JVM实例只有一块堆内存,堆也是Java内存管理的核心区域。Java堆区是在JVM启动时创建的,它的空间大小是确定的。它是JVM管理的最大的内存空间。堆内存的大小可以调整。《Java虚拟机规范》规定堆可以在物理上不连续的内存空间,但逻辑上应该认为是连续的。堆是GC(GarbageCollection,垃圾收集器)进行垃圾回收的关键区域。方法结束后,堆中的对象不会立即被移除,只会在垃圾回收时被移除。Java对象是不是都放在堆上了?《Java虚拟机规范》中对Java堆的描述是:所有的对象实例和数组在运行时都应该分配在堆上。(堆是运行时数据区域,从中分配所有类实例和数组的内存)数组和对象可能永远不会存储在堆栈中,因为堆栈帧在堆的位置保存对对象或数组的引用。我想说的是:“几乎”所有对象实例都在这里分配内存。——从实际使用的角度来看。示例:publicclassSimpleHeap{privateintid;publicSimpleHeap(intid){this.id=id;}publicvoidshow(){System.out.println("我的ID是"+id);}publicstaticvoidmain(String[]args){SimpleHeapsl=newSimpleHeap(1);SimpleHeaps2=newSimpleHeap(2);}}线程和堆的关系所有线程共享Java堆,这里也可以划分线程私有缓冲区(ThreadLocalAllocationBuffer,TLAB)。堆的内部结构大多数现代垃圾收集器都是基于分代收集理论设计的。堆空间细分为:Java7及之前堆内存在逻辑上分为三部分:新生区+老年代区+永久区YoungGenerationSpaceYoung/New分为Edenarea和SurvivorareaTenuregenerationspaceOld/TenurePermanentSpacePermanentareaPermJava8及之后的Heapmemory在逻辑上分为三部分:Newbornarea+oldagearea+metaspaceYoungGenerationSpaceYoungGenerationSpaceNewbornareaYoung/New分为Edenarea和SurvivorareaTenuregenerationspaceOld/TenureMeta空间元空间元协议:新生代区<=>新生代<=>年轻代退休区<=>老年区<=>老年代永久区<=>永久代理面试题Java堆的结构是什么样的?(猎聘)JVM内存为什么要分新生代、老年代、永久代。为什么新生代在Eden和Survivor(字节跳动)堆中分为分区:Eden、survivor(from+to)、oldgeneration,以及各自的特点。(JD-Logistics)堆的结构?为什么有两个幸存者区?(蚂蚁金服)Eden和Survivor比例分配(蚂蚁金服)JVM内存分区,为什么会有新生代和老年代(小米)JVM内存结构,Eden和Survivor比例。(京东)JVM内存为什么要分新生代、老年代、永久代。为什么新生代分为Eden和Survivor。(京东)JVM内存分区,为什么要有新生代和老年代?(美团)JVM的内存结构,Eden和Survivor的比例。(京东)新生代和老年代JVM中存储的Java对象可以分为两类:一类是瞬态对象,生命周期很短,这类对象的创建和消亡都非常快;另一类对象虽然有生命周期,但是很长,在某些极端情况下,可以和JVM的生命周期保持一致。如果Java堆区进一步细分,可以分为年轻代(YoungGen)和老年代(OldGen)。新生代可分为Eden空间、Survivor0空间和Survivor1空间(有时也称为fromarea,toarea)。几乎所有的Java对象都是在Eden区新建的。Java对象的大部分销毁是在新生代中进行的。IBM专项研究表明,新生代中80%的对象都是“生死存亡”。如何设置堆的大小?新生代与老年代的比例配置了新生代和老年代在堆结构中的比例。默认-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的1/3。可以修改-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/3。占整个堆的1/5,可以使用选项“-Xmn”来设置新生代的最大内存大小。该参数一般使用默认值。设置Eden和Survivor的比例在HotSpot中,Eden空间和另外两个Survivor空间的默认比例是8:1:1。当然,开发者可以通过选项“-XX:SurvivorRatio”来调整这个空间比例。例如-XX:SurvivorRatio=8常用参数堆空间大小的设置:-Xms:初始内存(默认为物理内存的1/64);-Xmx:最大内存(默认为物理内存的1/4);设置新生代的大小。(初始值和最大值)-Xmn通常是默认值。配置新生代和老年代在堆结构中的比例。分配的值是老年代占的比例,剩下的1分给新生代默认-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的1/3-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/5。在HotSpot中,Eden空间与另外两个Survivor空间的默认比例是8:1。“-XX:SurvivorRatio”调整这个空间比例。例如-XX:SurvivorRatio=8设置了新生代垃圾的最大年龄。如果超过这个值还没有被回收,就会进入老年代。默认值为15-XX:MaxTenuringThreshold=0:表示新生代对象直接进入老年代,不经过Survivor区。对于有很多老年代的应用程序,可以提高效率。如果该值设置较大,新生代对象会在Survivor区被多次复制,可以增加对象在新生代的存活时间,增加在新生代被回收的概率。输出详细的GC处理日志-XX:+PrintGcDetail-XX:HandlePromotionFailure在MinorGC发生前,虚拟机检查老年代最大可用连续空间是否大于新生代所有对象的总空间。如果大于,则MinorGC是安全的,如果小于,虚拟机会检查-XX:HandlePromotionFailure的设置值是否允许保证失败。如果HandlePromotionFailure=true,那么它会继续检查老年代的最大可用连续空间是否大于提升到老年代的对象的平均大小。如果较大,尝试进行一次MinorGC,但是这次MinorGC还是有风险的;如果小于或HandlePromotionFailure=false,则改为执行FullGC。----------------------JDK6Update24后,HandlePromotionFailure参数将不再影响虚拟机的空间分配保证策略。观察OpenJDK中的源代码变化。虽然在源代码中定义了HandlePromotionFailure参数,但代码中将不再使用。JDK6Update24之后的规则变成,只要老年代的连续空间大于新生代中对象的总大小或者之前提升的平均大小,就会进行MinorGC,否则进行FullGC.-XX:+PrintFlagsFinal:查看所有参数的最终值(可能有修改,不再是初始值)。具体查看一个参数的指令:jps:查看当前运行的进程jinfo-flagSurvivorRatio进程id对象被分配为为新对象分配内存是一项非常严谨和复杂的工作。JVM设计者不仅需要考虑如何分配内存、在何处分配内存,还需要考虑GC执行,因为内存分配算法与内存回收算法密切相关。内存回收后内存空间是否会产生内存碎片。金句:**幸存者s0和s1区总结:复制后有exchange,谁空谁to。关于垃圾回收:新区频繁回收,老区很少回收,永久区/元空间几乎不回收**分配过程1.新对象先放入伊甸园。该区域有大小限制。2.当Eden空间满了,程序需要重新创建对象。JVM垃圾回收器会对Eden区进行垃圾回收(MinorGC/YGC),回收Eden区中不再被其他对象引用的对象。破坏。然后将新的对象加载到Eden区3.然后将Eden区剩余的对象移动到survivor区0.4.如果再次触发垃圾回收,上次的survivor会被放到SurvivorZone0.如果没有被回收,它们会被放到Survivor1区。5.如果再经过垃圾回收,此时会放回Survivor0区,然后再去Survivor1区。6.什么时候可以去养老院?可以设置次数。默认为15次。可以设置参数:-XX:MaxTenuringThreshold=
