JVM内存板块分为5大块:JAVA堆、永久代、栈空间、本地方法栈、Cheap。

JAVA堆:又名Heap区,包括Young、old两大板块

永久代:、

栈空间:运行时线程私有栈空间

本地方法栈:C部分的代码区域

Cheap:非java区域的内存使用,有些JNI的调用会用到堆内存


Yong空间分为3个板块:1个Eden+2个Survivor区。

Eden区:使用new()或者newInstance()等方法创建的对象,默认都先将对象放到Eden区域的(除非对象太大,具体默认大小阈值-XX:PretenureSizeThreshold,超过阈值则放到old区)。

2个Survivor区又称S0、S1区。当Eden区域放满了就会做YoungGC(也称作MinorGC)。


位置总结:

1、当实例化一个对象时,对象大小没有达到阈值则会放入Eden区域。

2、第一次发生MinorGC时,会在S0或S1中选一个区域将Eden区域中活着的对象写入,(这里假定为S0),如果S0区域放不下了,则会放入Old区域,然后清空Eden区域。

3、第二次发生MinorGC时,会将“Eden区域+S0区域中活着的对象拷贝到S1”,如果S1区域放不下了,则会将对象放入Old区域,然后清空Eden区域和S0区域。

4、第三次发生MinorGC时,会将“Eden区域+S1区域中活着的对象拷贝到S0”,如果S0区域放不下了,则会将对象放入Old区域,然后清空Eden区域和S1区域,以此类推。


小结:

        1、通常情况下,FULLGC是我们不愿意看到的情况。如果写代码是有偏大的一些内存在使用,就会频繁导致FULLGC,例如:在多线程系统中,每个请求所对应的线程每次多几KB或几MB的空间,那么这些多出来的空间很快会被放到old区域,当old区域满了,就会做FULL GC操作。

        2、当Survivor区域放不下了,对象进入Old区域时,JVM会检查Old区域的内存空间是否足够,如果不足,就会做一次FULL GC操作。

        3、如果通过intern()方法,调用一个String对象,那么这个对象就会在Perm区域的常变量池中分配空间,当然它会通过equals保证唯一值。但是如果大量调用不同的String对象的Intern()方法,那么这些对象会在perm区域形成一份拷贝,逐步导致perm区域满,这块区域如果满了,就会做fullGC。 如果发生FULL GC时,没有引用指向String常量,则对象会回收,如果有,则就无法回收,最终导致OOM。

       4、Class对象也存储在Perm区域,如果动态加载大量的Class,而无法卸载的话,那么Perm区域也会满,自然也会FULLGC,甚至OOM(注:如果相关的ClassLoader下面的任意class对象还活着,那么它就不会被释放)

       5、线程的栈空间,这块空间是线程的私有空间,它会存放程序运行过程中的局部变量信息、先进后出栈。在程序运行过程中如果,递归调用,不断消耗栈空间,就会出现StackOverflowError的错误。