2.Heap(堆区)

  ~~~上一篇章了解到了JVM内存分布,之所以把堆区放在第二篇来讲,是因为堆在我们整个JVM学习过程中起着最为关键和重要的角色,同时对于我而言,这块有必要着重详细地记录下笔记。~~~

  学习java之初,我们知道类中创建的实例对象、数组都是存放在堆区(Heap),对象的引用、局部变量存放栈区(Stacks),类、方法、全局变量、静态变量、常量池存放在方法区(Metaspace)。

(ps~~~这是Java8之前的版本存储分布),看到对象,应该感到眼睛一亮吧。没错,java设计之初就是基于面对对象而开发的语言。那么,我们来好好看看这个堆吧。。。。。。


1. 堆区介绍

  堆,这块OOM(OutOfMemory)最主要发生的区域,它也是内存区域中最大的一块区域。被所有线程共享,存储着几乎所有的实例对象、数组,所有的对象实例以及数组都要在堆上分配,但是随着 JIT 编译器的发展与逃逸分析技术【JIT逃逸】逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。(ps:世事变化,凡事无绝对,否则打脸啪啪响)

  伴随着OOM的发生,自然需要垃圾回收,因此堆也是垃圾收集器管理的主要区域,也称为“GC堆”。从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以 Java 堆中还可以细分为:新生代老年代。再细一点,可以继续将新生代分为 Eden 空间From Survivor 空间(s0)To Survivor 空间(s1)等。从内存分配的角度来看,线程共享的 Java 堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。不过无论如何划分,都与存放内容无关,无论哪个区域,存储的都仍然是对象实例,进一步划分的目的是为了更好地回收内存,或者更快地分配内存。 


2.  堆区的默认空间分配 

 查看虚拟机的默认配置:

### java -XX:+PrintFlagsFinal -version

>java -XX:+PrintFlagsFinal -version
[Global flags]
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
 
     ..........
     ..........
     ..........

    uintx InitialBootClassLoaderMetaspaceSize       = 4194304                             {product}
    uintx InitialCodeCacheSize                      = 2555904                             {pd product}
    uintx InitialHeapSize                          := 201326592                           {product}
    uintx InitialRAMFraction                        = 64                                  {product}
    uintx InitialSurvivorRatio                      = 8                                   {product}
    uintx InitialTenuringThreshold                  = 7                                   {product}
    uintx InitiatingHeapOccupancyPercent            = 45                                  

     ..........
     ..........
     ..........

    uintx NewRatio                                  = 2                                  {product}
    uintx NewSize                                  := 67108864                           {product}
    uintx NewSizeThreadIncrease                     = 5320                               {pd product}

参数解释:


3. 堆区调整

  Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以在运行时动态地调整。事实上,为满足程序性能上的最优化,也有必要去调整。

  通过设置如下参数,可以设定堆区的初始值和最大值,比如 -Xms256M -Xmx 1024M,其中 -X 这个字母代表它是 JVM 运行时参数,ms 是 memory start 的简称,中文意思就是内存初始值,mx 是 memory max 的简称,意思就是最大内存。 在通常情况下,服务器在运行过程中,堆空间不断地扩容与回缩,会形成不必要的系统压力所以在线上生产环境中 JVM 的 Xms 和 Xmx 会设置成同样大小,避免在 GC 后调整堆大小时带来的额外压力。


4. 创建对象的分配流程

  

   绝大部分对象在 Eden 区生成,当 Eden 区装填满的时候,会触发 Young Garbage Collection,即 YGC。垃圾回收的时候,在 Eden 区实现清除策略,没有被引用的对象则直接回收。依然存活的对象会被移送到 Survivor 区。Survivor 区分为 so 和 s1 两块内存空间。每次 YGC 的时候,它们将存活的对象复制到未使用的那块空间,然后将当前正在使用的空间完全清除,交换两块空间的使用状态。如果 YGC 要移送的对象大于 Survivor 区容量的上限,则直接移交给老年代。一个对象也不可能永远呆在新生代,就像人到了 18 岁就会成年一样,在 JVM 中 -XX:MaxTenuringThreshold 参数就是来配置一个对象从新生代晋升到老年代的阈值。默认值是 15,可以在 Survivor 区交换 14 次之后,晋升至老年代。

**************************************************************************************************************************************************

  技术之路从来就没有捷径可言,从事java工作四年快五年了,荒废了不少时间,也深刻迫切感到压力。以前总是很浮躁,但这对于技术学习来说,却是最为致命的。希望为时还不晚,今后系统学习,点滴积累,从基础到扩展,慢慢量变到质变。学习过程中,参考了很多前辈大牛的文章,如觉得侵权积累知识行为,一方面希望多多包涵,另一方面也麻烦告知删除,Thanks~~~,另外特别感谢Richard_Yi大神博客指导2333

  

    

猜你喜欢

转载自www.cnblogs.com/light-sunset/p/12771207.html