JVM内存分配浅谈

这里写图片描述
1:首先途中红色区块是线程私有的,绿色的方法区和堆区是线程共享的;
2:接下来是内存各部分的介绍:

(1)堆区(Heap)

线程共享。新生代(Eden),大部分对象的创建都再新生代的Eden区,当Eden区满后就会触发新生代的Minor GC(次回收),将Eden区和非空闲Survivor区存活的对象复制到另外一个空闲的Survivor区中。保证一个Survivor是空的,新生代Minor GC就是在两个Survivor区之间相互复制存活对象,直到Survivor区满为止。一个对象经历多次Minor GC后变成老年代。

老年代(Old Memory)
当Survivor区也满了之后就通过Minor GC将对象复制到老年代。老年代也满了的话,就将触发Full GC(全回收)

FULL GC针对整个堆(包括新生代、老年代)进行垃圾回收


持久代((perm))
不属于堆内存,持久代如果满了,将触发Full GC。(持久代满是因为动态加载了太多类)JDK7后被取消了

顺便了解下垃圾回收机制:
(1)回收方式。首先要知道垃圾回收又两种方式:Minor GC(次回收)和Full GC(全回收)。次回收触发条件是年轻代满了,收集时间短;全回收触发条件是老年代满,持久代满了。
(2)针对的对象。垃圾回收针对的是不再使用的对象和超出作用域的对象。
(3)做了什么事。垃圾回收的过程中删除不再使用的对象,停止其他线程的运行,运行finalize方法等等
(4)OOM的调用。对象的回收都需要一定的时间,gc与非gc时间耗时超过了GCTimeRatio的限制引发OOM,调优诸如通过NewRatio控制新生代老年代比例,通过MaxTenuringThreshold控制进入老年前生存次数等
(5)垃圾回收线程的优先级非常低

内存溢出错误(OutOfMemoryError)
当一个应用耗尽了内存并且JVM GC也无法回收任何对象空间的时候,就会发生内存溢出错误。但是,内存溢出错误并不一定就意味着内存泄露(memory leak)。也有可能只是一个配置问题,例如设置的堆大小(如果没有设置那就是缺省的堆大小)对于应用来说是不够用的。


(2)虚拟机栈内存
线程私有。就是我们平常说的栈。存放基本数据类型的变量,和对象的引用。方法也存在进栈和出栈的过程

(3)方法区
线程共享。方法区与Java堆一样,是各个线程共享的区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译(JIT)后的代码等数据。(所以说static方法和变两都存放在这里)
虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

(4)程序计数器
线程私有。程序计数器(ProgramCounterRegister)的作用可以看做是当前线程所执行的字节码的行号指示器。
由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

(5)本地方法栈
线程私有。本地方法栈(NativeMethodStacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

注意
为什么要有两个Survivor请参考文章:
https://blog.csdn.net/antony9118/article/details/51425581

常见的名词知识点:


Xmx是堆最大大小,Xms是初始堆大小,Xmn是年轻代大小,-XXSurvivorRatio:
年轻代中Eden区与Survivor区的大小比值


猜你喜欢

转载自blog.csdn.net/IM_MESSI/article/details/81699723
今日推荐