作为一个java开发人员,懂不懂java内存分配成为你是否为高级java工程师的标准。为什么这么说呢?因为java虚拟机(也就是jvm)有着自己的自动内存管理机制,在我们写代码的过程中不会去管理内存的分配和回收,所以如果想进行性能调优或者内存问题的排查就必须了解内存的分配了,而内存的回收要和垃圾收集器一起学。自己是看了《深入理解Java虚拟机》周志明 著 第2版 来了解的。这本书真的不负盛名。值得一看。在这里也推荐给读者。而java内存分配实在不好在一篇文章中讲完。而此篇文章纯粹为笔记吧。
首先要知道java中内存分配和回收都主要是在java堆上。java堆是jvm管理中内存最大的一块。那在java堆中,分内存为2部分,也就是大名鼎鼎的新生代和老年代了。而在新生代中分为Eden空间、From Survivor 空间、To Survivor空间。为了方便理解,下面有一个图。
其中From指的就是From Survivor空间,而To同理。看到这里的时候,你会不会疑问说为什么java堆为什么要分成新生代和老年代 ,而新生代中又分为2个Survivor空间呢?原因在于内存的回收。讲明白这里的话需要了解jvm中几种垃圾收集器的原理了,在这里先不展开讲。
像我们平时new一个对象出来的时候,jvm一般会怎么做呢?有2个策略:
- 对象you优先在Eden分配。
- 大对象直接进入老年代
如果对象所需要的空间超出了Eden的剩余空间,则会进行一次Minor GC,也就是我们说的young GC或者说新生代GC。这样会把一些对象回收到Survivor空间去,再看看多出来的空间够不够对象所需的空间。要是一个对象所需内存空间较大,这就是大对象,直接分配到老年代去。
而内存的分配不仅仅和大小有关,还有时间的这个维度。在这里有2个策略:
- chan长期存活的对象将进入老年代
- 动态的对对象进行年龄判定
jvm在分配对象内存的时候,还会给对象一个年龄计数器,如果对象分配在Eden空间,经过第一次MinorGC后被分配到Survivor空间,在此时就是把对象年龄设为1,。对象在Survivor空间中每过一次MinorGC,并且没有被移动到老年代去,ni年龄就增加1岁。当到达一定年龄,就会移动到老年代去。而这个阈值可以通过-XX:MaxTenuringThreshold设置。
而动态的判定是怎么回事呢?如果在Survivorkong空间中相同年龄所有对象大小的总和大于Survivorkon空间的一般,年龄大于或等于ga该年龄的对象就可以直接进入老年代。这时候就不会说一定要到达设定的年龄了。
内存的分配大概就是这样的流程了。其实写这篇文章花了很长时间,因为自己一直在犹豫要不要将很多细节展开来躲描述一下。但是又怕自己一展开,总是像打开一扇新世界的大门。这样就不知道怎么才能收尾了。所以索性就当做一篇笔记来写吧。
沁园春 雪 (1936.02 )
北国风光,千里冰封,万里雪飘。
望长城内外,惟馀莽莽;大河上下,顿失滔滔。
山舞银蛇,原驰蜡象,欲与天公试比高。
须晴日,看红妆素裹,分外妖娆。
江山如此多娇,
引无数英雄竞折腰。
惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。
一代天骄,成吉思汗,只识弯弓射大雕。
俱往矣,数风流人物,还看今朝。